18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <dirent.h> 38c2ecf20Sopenharmony_ci#include <errno.h> 48c2ecf20Sopenharmony_ci#include <inttypes.h> 58c2ecf20Sopenharmony_ci#include <regex.h> 68c2ecf20Sopenharmony_ci#include <stdlib.h> 78c2ecf20Sopenharmony_ci#include "callchain.h" 88c2ecf20Sopenharmony_ci#include "debug.h" 98c2ecf20Sopenharmony_ci#include "dso.h" 108c2ecf20Sopenharmony_ci#include "env.h" 118c2ecf20Sopenharmony_ci#include "event.h" 128c2ecf20Sopenharmony_ci#include "evsel.h" 138c2ecf20Sopenharmony_ci#include "hist.h" 148c2ecf20Sopenharmony_ci#include "machine.h" 158c2ecf20Sopenharmony_ci#include "map.h" 168c2ecf20Sopenharmony_ci#include "map_symbol.h" 178c2ecf20Sopenharmony_ci#include "branch.h" 188c2ecf20Sopenharmony_ci#include "mem-events.h" 198c2ecf20Sopenharmony_ci#include "srcline.h" 208c2ecf20Sopenharmony_ci#include "symbol.h" 218c2ecf20Sopenharmony_ci#include "sort.h" 228c2ecf20Sopenharmony_ci#include "strlist.h" 238c2ecf20Sopenharmony_ci#include "target.h" 248c2ecf20Sopenharmony_ci#include "thread.h" 258c2ecf20Sopenharmony_ci#include "util.h" 268c2ecf20Sopenharmony_ci#include "vdso.h" 278c2ecf20Sopenharmony_ci#include <stdbool.h> 288c2ecf20Sopenharmony_ci#include <sys/types.h> 298c2ecf20Sopenharmony_ci#include <sys/stat.h> 308c2ecf20Sopenharmony_ci#include <unistd.h> 318c2ecf20Sopenharmony_ci#include "unwind.h" 328c2ecf20Sopenharmony_ci#include "linux/hash.h" 338c2ecf20Sopenharmony_ci#include "asm/bug.h" 348c2ecf20Sopenharmony_ci#include "bpf-event.h" 358c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size 368c2ecf20Sopenharmony_ci#include "cgroup.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <linux/ctype.h> 398c2ecf20Sopenharmony_ci#include <symbol/kallsyms.h> 408c2ecf20Sopenharmony_ci#include <linux/mman.h> 418c2ecf20Sopenharmony_ci#include <linux/string.h> 428c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic struct dso *machine__kernel_dso(struct machine *machine) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci return machine->vmlinux_map->dso; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void dsos__init(struct dsos *dsos) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dsos->head); 548c2ecf20Sopenharmony_ci dsos->root = RB_ROOT; 558c2ecf20Sopenharmony_ci init_rwsem(&dsos->lock); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void machine__threads_init(struct machine *machine) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci int i; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 638c2ecf20Sopenharmony_ci struct threads *threads = &machine->threads[i]; 648c2ecf20Sopenharmony_ci threads->entries = RB_ROOT_CACHED; 658c2ecf20Sopenharmony_ci init_rwsem(&threads->lock); 668c2ecf20Sopenharmony_ci threads->nr = 0; 678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&threads->dead); 688c2ecf20Sopenharmony_ci threads->last_match = NULL; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int machine__set_mmap_name(struct machine *machine) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci if (machine__is_host(machine)) 758c2ecf20Sopenharmony_ci machine->mmap_name = strdup("[kernel.kallsyms]"); 768c2ecf20Sopenharmony_ci else if (machine__is_default_guest(machine)) 778c2ecf20Sopenharmony_ci machine->mmap_name = strdup("[guest.kernel.kallsyms]"); 788c2ecf20Sopenharmony_ci else if (asprintf(&machine->mmap_name, "[guest.kernel.kallsyms.%d]", 798c2ecf20Sopenharmony_ci machine->pid) < 0) 808c2ecf20Sopenharmony_ci machine->mmap_name = NULL; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return machine->mmap_name ? 0 : -ENOMEM; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ciint machine__init(struct machine *machine, const char *root_dir, pid_t pid) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci int err = -ENOMEM; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci memset(machine, 0, sizeof(*machine)); 908c2ecf20Sopenharmony_ci maps__init(&machine->kmaps, machine); 918c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&machine->rb_node); 928c2ecf20Sopenharmony_ci dsos__init(&machine->dsos); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci machine__threads_init(machine); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci machine->vdso_info = NULL; 978c2ecf20Sopenharmony_ci machine->env = NULL; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci machine->pid = pid; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci machine->id_hdr_size = 0; 1028c2ecf20Sopenharmony_ci machine->kptr_restrict_warned = false; 1038c2ecf20Sopenharmony_ci machine->comm_exec = false; 1048c2ecf20Sopenharmony_ci machine->kernel_start = 0; 1058c2ecf20Sopenharmony_ci machine->vmlinux_map = NULL; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci machine->root_dir = strdup(root_dir); 1088c2ecf20Sopenharmony_ci if (machine->root_dir == NULL) 1098c2ecf20Sopenharmony_ci return -ENOMEM; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (machine__set_mmap_name(machine)) 1128c2ecf20Sopenharmony_ci goto out; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (pid != HOST_KERNEL_ID) { 1158c2ecf20Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, -1, 1168c2ecf20Sopenharmony_ci pid); 1178c2ecf20Sopenharmony_ci char comm[64]; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (thread == NULL) 1208c2ecf20Sopenharmony_ci goto out; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci snprintf(comm, sizeof(comm), "[guest/%d]", pid); 1238c2ecf20Sopenharmony_ci thread__set_comm(thread, comm, 0); 1248c2ecf20Sopenharmony_ci thread__put(thread); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci machine->current_tid = NULL; 1288c2ecf20Sopenharmony_ci err = 0; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ciout: 1318c2ecf20Sopenharmony_ci if (err) { 1328c2ecf20Sopenharmony_ci zfree(&machine->root_dir); 1338c2ecf20Sopenharmony_ci zfree(&machine->mmap_name); 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistruct machine *machine__new_host(void) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct machine *machine = malloc(sizeof(*machine)); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (machine != NULL) { 1438c2ecf20Sopenharmony_ci machine__init(machine, "", HOST_KERNEL_ID); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (machine__create_kernel_maps(machine) < 0) 1468c2ecf20Sopenharmony_ci goto out_delete; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return machine; 1508c2ecf20Sopenharmony_ciout_delete: 1518c2ecf20Sopenharmony_ci free(machine); 1528c2ecf20Sopenharmony_ci return NULL; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistruct machine *machine__new_kallsyms(void) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci struct machine *machine = machine__new_host(); 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * FIXME: 1608c2ecf20Sopenharmony_ci * 1) We should switch to machine__load_kallsyms(), i.e. not explicitly 1618c2ecf20Sopenharmony_ci * ask for not using the kcore parsing code, once this one is fixed 1628c2ecf20Sopenharmony_ci * to create a map per module. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ci if (machine && machine__load_kallsyms(machine, "/proc/kallsyms") <= 0) { 1658c2ecf20Sopenharmony_ci machine__delete(machine); 1668c2ecf20Sopenharmony_ci machine = NULL; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return machine; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic void dsos__purge(struct dsos *dsos) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct dso *pos, *n; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci down_write(&dsos->lock); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci list_for_each_entry_safe(pos, n, &dsos->head, node) { 1798c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&pos->rb_node); 1808c2ecf20Sopenharmony_ci pos->root = NULL; 1818c2ecf20Sopenharmony_ci list_del_init(&pos->node); 1828c2ecf20Sopenharmony_ci dso__put(pos); 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci up_write(&dsos->lock); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic void dsos__exit(struct dsos *dsos) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci dsos__purge(dsos); 1918c2ecf20Sopenharmony_ci exit_rwsem(&dsos->lock); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_civoid machine__delete_threads(struct machine *machine) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct rb_node *nd; 1978c2ecf20Sopenharmony_ci int i; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 2008c2ecf20Sopenharmony_ci struct threads *threads = &machine->threads[i]; 2018c2ecf20Sopenharmony_ci down_write(&threads->lock); 2028c2ecf20Sopenharmony_ci nd = rb_first_cached(&threads->entries); 2038c2ecf20Sopenharmony_ci while (nd) { 2048c2ecf20Sopenharmony_ci struct thread *t = rb_entry(nd, struct thread, rb_node); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci nd = rb_next(nd); 2078c2ecf20Sopenharmony_ci __machine__remove_thread(machine, t, false); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci up_write(&threads->lock); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_civoid machine__exit(struct machine *machine) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int i; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (machine == NULL) 2188c2ecf20Sopenharmony_ci return; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci machine__destroy_kernel_maps(machine); 2218c2ecf20Sopenharmony_ci maps__exit(&machine->kmaps); 2228c2ecf20Sopenharmony_ci dsos__exit(&machine->dsos); 2238c2ecf20Sopenharmony_ci machine__exit_vdso(machine); 2248c2ecf20Sopenharmony_ci zfree(&machine->root_dir); 2258c2ecf20Sopenharmony_ci zfree(&machine->mmap_name); 2268c2ecf20Sopenharmony_ci zfree(&machine->current_tid); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 2298c2ecf20Sopenharmony_ci struct threads *threads = &machine->threads[i]; 2308c2ecf20Sopenharmony_ci struct thread *thread, *n; 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * Forget about the dead, at this point whatever threads were 2338c2ecf20Sopenharmony_ci * left in the dead lists better have a reference count taken 2348c2ecf20Sopenharmony_ci * by who is using them, and then, when they drop those references 2358c2ecf20Sopenharmony_ci * and it finally hits zero, thread__put() will check and see that 2368c2ecf20Sopenharmony_ci * its not in the dead threads list and will not try to remove it 2378c2ecf20Sopenharmony_ci * from there, just calling thread__delete() straight away. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci list_for_each_entry_safe(thread, n, &threads->dead, node) 2408c2ecf20Sopenharmony_ci list_del_init(&thread->node); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci exit_rwsem(&threads->lock); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_civoid machine__delete(struct machine *machine) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci if (machine) { 2498c2ecf20Sopenharmony_ci machine__exit(machine); 2508c2ecf20Sopenharmony_ci free(machine); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_civoid machines__init(struct machines *machines) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci machine__init(&machines->host, "", HOST_KERNEL_ID); 2578c2ecf20Sopenharmony_ci machines->guests = RB_ROOT_CACHED; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_civoid machines__exit(struct machines *machines) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci machine__exit(&machines->host); 2638c2ecf20Sopenharmony_ci /* XXX exit guest */ 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistruct machine *machines__add(struct machines *machines, pid_t pid, 2678c2ecf20Sopenharmony_ci const char *root_dir) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct rb_node **p = &machines->guests.rb_root.rb_node; 2708c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 2718c2ecf20Sopenharmony_ci struct machine *pos, *machine = malloc(sizeof(*machine)); 2728c2ecf20Sopenharmony_ci bool leftmost = true; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (machine == NULL) 2758c2ecf20Sopenharmony_ci return NULL; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (machine__init(machine, root_dir, pid) != 0) { 2788c2ecf20Sopenharmony_ci free(machine); 2798c2ecf20Sopenharmony_ci return NULL; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci while (*p != NULL) { 2838c2ecf20Sopenharmony_ci parent = *p; 2848c2ecf20Sopenharmony_ci pos = rb_entry(parent, struct machine, rb_node); 2858c2ecf20Sopenharmony_ci if (pid < pos->pid) 2868c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 2878c2ecf20Sopenharmony_ci else { 2888c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 2898c2ecf20Sopenharmony_ci leftmost = false; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci rb_link_node(&machine->rb_node, parent, p); 2948c2ecf20Sopenharmony_ci rb_insert_color_cached(&machine->rb_node, &machines->guests, leftmost); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return machine; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_civoid machines__set_comm_exec(struct machines *machines, bool comm_exec) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct rb_node *nd; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci machines->host.comm_exec = comm_exec; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 3068c2ecf20Sopenharmony_ci struct machine *machine = rb_entry(nd, struct machine, rb_node); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci machine->comm_exec = comm_exec; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistruct machine *machines__find(struct machines *machines, pid_t pid) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct rb_node **p = &machines->guests.rb_root.rb_node; 3158c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 3168c2ecf20Sopenharmony_ci struct machine *machine; 3178c2ecf20Sopenharmony_ci struct machine *default_machine = NULL; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (pid == HOST_KERNEL_ID) 3208c2ecf20Sopenharmony_ci return &machines->host; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci while (*p != NULL) { 3238c2ecf20Sopenharmony_ci parent = *p; 3248c2ecf20Sopenharmony_ci machine = rb_entry(parent, struct machine, rb_node); 3258c2ecf20Sopenharmony_ci if (pid < machine->pid) 3268c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 3278c2ecf20Sopenharmony_ci else if (pid > machine->pid) 3288c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 3298c2ecf20Sopenharmony_ci else 3308c2ecf20Sopenharmony_ci return machine; 3318c2ecf20Sopenharmony_ci if (!machine->pid) 3328c2ecf20Sopenharmony_ci default_machine = machine; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return default_machine; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistruct machine *machines__findnew(struct machines *machines, pid_t pid) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci char path[PATH_MAX]; 3418c2ecf20Sopenharmony_ci const char *root_dir = ""; 3428c2ecf20Sopenharmony_ci struct machine *machine = machines__find(machines, pid); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if (machine && (machine->pid == pid)) 3458c2ecf20Sopenharmony_ci goto out; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if ((pid != HOST_KERNEL_ID) && 3488c2ecf20Sopenharmony_ci (pid != DEFAULT_GUEST_KERNEL_ID) && 3498c2ecf20Sopenharmony_ci (symbol_conf.guestmount)) { 3508c2ecf20Sopenharmony_ci sprintf(path, "%s/%d", symbol_conf.guestmount, pid); 3518c2ecf20Sopenharmony_ci if (access(path, R_OK)) { 3528c2ecf20Sopenharmony_ci static struct strlist *seen; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (!seen) 3558c2ecf20Sopenharmony_ci seen = strlist__new(NULL, NULL); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (!strlist__has_entry(seen, path)) { 3588c2ecf20Sopenharmony_ci pr_err("Can't access file %s\n", path); 3598c2ecf20Sopenharmony_ci strlist__add(seen, path); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci machine = NULL; 3628c2ecf20Sopenharmony_ci goto out; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci root_dir = path; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci machine = machines__add(machines, pid, root_dir); 3688c2ecf20Sopenharmony_ciout: 3698c2ecf20Sopenharmony_ci return machine; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_civoid machines__process_guests(struct machines *machines, 3738c2ecf20Sopenharmony_ci machine__process_t process, void *data) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct rb_node *nd; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 3788c2ecf20Sopenharmony_ci struct machine *pos = rb_entry(nd, struct machine, rb_node); 3798c2ecf20Sopenharmony_ci process(pos, data); 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_civoid machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct rb_node *node; 3868c2ecf20Sopenharmony_ci struct machine *machine; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci machines->host.id_hdr_size = id_hdr_size; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci for (node = rb_first_cached(&machines->guests); node; 3918c2ecf20Sopenharmony_ci node = rb_next(node)) { 3928c2ecf20Sopenharmony_ci machine = rb_entry(node, struct machine, rb_node); 3938c2ecf20Sopenharmony_ci machine->id_hdr_size = id_hdr_size; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void machine__update_thread_pid(struct machine *machine, 4008c2ecf20Sopenharmony_ci struct thread *th, pid_t pid) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct thread *leader; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (pid == th->pid_ || pid == -1 || th->pid_ != -1) 4058c2ecf20Sopenharmony_ci return; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci th->pid_ = pid; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (th->pid_ == th->tid) 4108c2ecf20Sopenharmony_ci return; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci leader = __machine__findnew_thread(machine, th->pid_, th->pid_); 4138c2ecf20Sopenharmony_ci if (!leader) 4148c2ecf20Sopenharmony_ci goto out_err; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (!leader->maps) 4178c2ecf20Sopenharmony_ci leader->maps = maps__new(machine); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!leader->maps) 4208c2ecf20Sopenharmony_ci goto out_err; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (th->maps == leader->maps) 4238c2ecf20Sopenharmony_ci return; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (th->maps) { 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * Maps are created from MMAP events which provide the pid and 4288c2ecf20Sopenharmony_ci * tid. Consequently there never should be any maps on a thread 4298c2ecf20Sopenharmony_ci * with an unknown pid. Just print an error if there are. 4308c2ecf20Sopenharmony_ci */ 4318c2ecf20Sopenharmony_ci if (!maps__empty(th->maps)) 4328c2ecf20Sopenharmony_ci pr_err("Discarding thread maps for %d:%d\n", 4338c2ecf20Sopenharmony_ci th->pid_, th->tid); 4348c2ecf20Sopenharmony_ci maps__put(th->maps); 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci th->maps = maps__get(leader->maps); 4388c2ecf20Sopenharmony_ciout_put: 4398c2ecf20Sopenharmony_ci thread__put(leader); 4408c2ecf20Sopenharmony_ci return; 4418c2ecf20Sopenharmony_ciout_err: 4428c2ecf20Sopenharmony_ci pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid); 4438c2ecf20Sopenharmony_ci goto out_put; 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* 4478c2ecf20Sopenharmony_ci * Front-end cache - TID lookups come in blocks, 4488c2ecf20Sopenharmony_ci * so most of the time we dont have to look up 4498c2ecf20Sopenharmony_ci * the full rbtree: 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_cistatic struct thread* 4528c2ecf20Sopenharmony_ci__threads__get_last_match(struct threads *threads, struct machine *machine, 4538c2ecf20Sopenharmony_ci int pid, int tid) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct thread *th; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci th = threads->last_match; 4588c2ecf20Sopenharmony_ci if (th != NULL) { 4598c2ecf20Sopenharmony_ci if (th->tid == tid) { 4608c2ecf20Sopenharmony_ci machine__update_thread_pid(machine, th, pid); 4618c2ecf20Sopenharmony_ci return thread__get(th); 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci threads->last_match = NULL; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return NULL; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic struct thread* 4718c2ecf20Sopenharmony_cithreads__get_last_match(struct threads *threads, struct machine *machine, 4728c2ecf20Sopenharmony_ci int pid, int tid) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci struct thread *th = NULL; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci if (perf_singlethreaded) 4778c2ecf20Sopenharmony_ci th = __threads__get_last_match(threads, machine, pid, tid); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci return th; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic void 4838c2ecf20Sopenharmony_ci__threads__set_last_match(struct threads *threads, struct thread *th) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci threads->last_match = th; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic void 4898c2ecf20Sopenharmony_cithreads__set_last_match(struct threads *threads, struct thread *th) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci if (perf_singlethreaded) 4928c2ecf20Sopenharmony_ci __threads__set_last_match(threads, th); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/* 4968c2ecf20Sopenharmony_ci * Caller must eventually drop thread->refcnt returned with a successful 4978c2ecf20Sopenharmony_ci * lookup/new thread inserted. 4988c2ecf20Sopenharmony_ci */ 4998c2ecf20Sopenharmony_cistatic struct thread *____machine__findnew_thread(struct machine *machine, 5008c2ecf20Sopenharmony_ci struct threads *threads, 5018c2ecf20Sopenharmony_ci pid_t pid, pid_t tid, 5028c2ecf20Sopenharmony_ci bool create) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct rb_node **p = &threads->entries.rb_root.rb_node; 5058c2ecf20Sopenharmony_ci struct rb_node *parent = NULL; 5068c2ecf20Sopenharmony_ci struct thread *th; 5078c2ecf20Sopenharmony_ci bool leftmost = true; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci th = threads__get_last_match(threads, machine, pid, tid); 5108c2ecf20Sopenharmony_ci if (th) 5118c2ecf20Sopenharmony_ci return th; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci while (*p != NULL) { 5148c2ecf20Sopenharmony_ci parent = *p; 5158c2ecf20Sopenharmony_ci th = rb_entry(parent, struct thread, rb_node); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (th->tid == tid) { 5188c2ecf20Sopenharmony_ci threads__set_last_match(threads, th); 5198c2ecf20Sopenharmony_ci machine__update_thread_pid(machine, th, pid); 5208c2ecf20Sopenharmony_ci return thread__get(th); 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (tid < th->tid) 5248c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 5258c2ecf20Sopenharmony_ci else { 5268c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 5278c2ecf20Sopenharmony_ci leftmost = false; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (!create) 5328c2ecf20Sopenharmony_ci return NULL; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci th = thread__new(pid, tid); 5358c2ecf20Sopenharmony_ci if (th != NULL) { 5368c2ecf20Sopenharmony_ci rb_link_node(&th->rb_node, parent, p); 5378c2ecf20Sopenharmony_ci rb_insert_color_cached(&th->rb_node, &threads->entries, leftmost); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * We have to initialize maps separately after rb tree is updated. 5418c2ecf20Sopenharmony_ci * 5428c2ecf20Sopenharmony_ci * The reason is that we call machine__findnew_thread 5438c2ecf20Sopenharmony_ci * within thread__init_maps to find the thread 5448c2ecf20Sopenharmony_ci * leader and that would screwed the rb tree. 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_ci if (thread__init_maps(th, machine)) { 5478c2ecf20Sopenharmony_ci rb_erase_cached(&th->rb_node, &threads->entries); 5488c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&th->rb_node); 5498c2ecf20Sopenharmony_ci thread__put(th); 5508c2ecf20Sopenharmony_ci return NULL; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci /* 5538c2ecf20Sopenharmony_ci * It is now in the rbtree, get a ref 5548c2ecf20Sopenharmony_ci */ 5558c2ecf20Sopenharmony_ci thread__get(th); 5568c2ecf20Sopenharmony_ci threads__set_last_match(threads, th); 5578c2ecf20Sopenharmony_ci ++threads->nr; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci return th; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistruct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci return ____machine__findnew_thread(machine, machine__threads(machine, tid), pid, tid, true); 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistruct thread *machine__findnew_thread(struct machine *machine, pid_t pid, 5698c2ecf20Sopenharmony_ci pid_t tid) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct threads *threads = machine__threads(machine, tid); 5728c2ecf20Sopenharmony_ci struct thread *th; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci down_write(&threads->lock); 5758c2ecf20Sopenharmony_ci th = __machine__findnew_thread(machine, pid, tid); 5768c2ecf20Sopenharmony_ci up_write(&threads->lock); 5778c2ecf20Sopenharmony_ci return th; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistruct thread *machine__find_thread(struct machine *machine, pid_t pid, 5818c2ecf20Sopenharmony_ci pid_t tid) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct threads *threads = machine__threads(machine, tid); 5848c2ecf20Sopenharmony_ci struct thread *th; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci down_read(&threads->lock); 5878c2ecf20Sopenharmony_ci th = ____machine__findnew_thread(machine, threads, pid, tid, false); 5888c2ecf20Sopenharmony_ci up_read(&threads->lock); 5898c2ecf20Sopenharmony_ci return th; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistruct comm *machine__thread_exec_comm(struct machine *machine, 5938c2ecf20Sopenharmony_ci struct thread *thread) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci if (machine->comm_exec) 5968c2ecf20Sopenharmony_ci return thread__exec_comm(thread); 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci return thread__comm(thread); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ciint machine__process_comm_event(struct machine *machine, union perf_event *event, 6028c2ecf20Sopenharmony_ci struct perf_sample *sample) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, 6058c2ecf20Sopenharmony_ci event->comm.pid, 6068c2ecf20Sopenharmony_ci event->comm.tid); 6078c2ecf20Sopenharmony_ci bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; 6088c2ecf20Sopenharmony_ci int err = 0; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (exec) 6118c2ecf20Sopenharmony_ci machine->comm_exec = true; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (dump_trace) 6148c2ecf20Sopenharmony_ci perf_event__fprintf_comm(event, stdout); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (thread == NULL || 6178c2ecf20Sopenharmony_ci __thread__set_comm(thread, event->comm.comm, sample->time, exec)) { 6188c2ecf20Sopenharmony_ci dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 6198c2ecf20Sopenharmony_ci err = -1; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci thread__put(thread); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return err; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ciint machine__process_namespaces_event(struct machine *machine __maybe_unused, 6288c2ecf20Sopenharmony_ci union perf_event *event, 6298c2ecf20Sopenharmony_ci struct perf_sample *sample __maybe_unused) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, 6328c2ecf20Sopenharmony_ci event->namespaces.pid, 6338c2ecf20Sopenharmony_ci event->namespaces.tid); 6348c2ecf20Sopenharmony_ci int err = 0; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci WARN_ONCE(event->namespaces.nr_namespaces > NR_NAMESPACES, 6378c2ecf20Sopenharmony_ci "\nWARNING: kernel seems to support more namespaces than perf" 6388c2ecf20Sopenharmony_ci " tool.\nTry updating the perf tool..\n\n"); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES, 6418c2ecf20Sopenharmony_ci "\nWARNING: perf tool seems to support more namespaces than" 6428c2ecf20Sopenharmony_ci " the kernel.\nTry updating the kernel..\n\n"); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (dump_trace) 6458c2ecf20Sopenharmony_ci perf_event__fprintf_namespaces(event, stdout); 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (thread == NULL || 6488c2ecf20Sopenharmony_ci thread__set_namespaces(thread, sample->time, &event->namespaces)) { 6498c2ecf20Sopenharmony_ci dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n"); 6508c2ecf20Sopenharmony_ci err = -1; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci thread__put(thread); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return err; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ciint machine__process_cgroup_event(struct machine *machine, 6598c2ecf20Sopenharmony_ci union perf_event *event, 6608c2ecf20Sopenharmony_ci struct perf_sample *sample __maybe_unused) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct cgroup *cgrp; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci if (dump_trace) 6658c2ecf20Sopenharmony_ci perf_event__fprintf_cgroup(event, stdout); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci cgrp = cgroup__findnew(machine->env, event->cgroup.id, event->cgroup.path); 6688c2ecf20Sopenharmony_ci if (cgrp == NULL) 6698c2ecf20Sopenharmony_ci return -ENOMEM; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return 0; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ciint machine__process_lost_event(struct machine *machine __maybe_unused, 6758c2ecf20Sopenharmony_ci union perf_event *event, struct perf_sample *sample __maybe_unused) 6768c2ecf20Sopenharmony_ci{ 6778c2ecf20Sopenharmony_ci dump_printf(": id:%" PRI_lu64 ": lost:%" PRI_lu64 "\n", 6788c2ecf20Sopenharmony_ci event->lost.id, event->lost.lost); 6798c2ecf20Sopenharmony_ci return 0; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ciint machine__process_lost_samples_event(struct machine *machine __maybe_unused, 6838c2ecf20Sopenharmony_ci union perf_event *event, struct perf_sample *sample) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci dump_printf(": id:%" PRIu64 ": lost samples :%" PRI_lu64 "\n", 6868c2ecf20Sopenharmony_ci sample->id, event->lost_samples.lost); 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic struct dso *machine__findnew_module_dso(struct machine *machine, 6918c2ecf20Sopenharmony_ci struct kmod_path *m, 6928c2ecf20Sopenharmony_ci const char *filename) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct dso *dso; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci down_write(&machine->dsos.lock); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci dso = __dsos__find(&machine->dsos, m->name, true); 6998c2ecf20Sopenharmony_ci if (!dso) { 7008c2ecf20Sopenharmony_ci dso = __dsos__addnew(&machine->dsos, m->name); 7018c2ecf20Sopenharmony_ci if (dso == NULL) 7028c2ecf20Sopenharmony_ci goto out_unlock; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci dso__set_module_info(dso, m, machine); 7058c2ecf20Sopenharmony_ci dso__set_long_name(dso, strdup(filename), true); 7068c2ecf20Sopenharmony_ci dso->kernel = DSO_SPACE__KERNEL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci dso__get(dso); 7108c2ecf20Sopenharmony_ciout_unlock: 7118c2ecf20Sopenharmony_ci up_write(&machine->dsos.lock); 7128c2ecf20Sopenharmony_ci return dso; 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ciint machine__process_aux_event(struct machine *machine __maybe_unused, 7168c2ecf20Sopenharmony_ci union perf_event *event) 7178c2ecf20Sopenharmony_ci{ 7188c2ecf20Sopenharmony_ci if (dump_trace) 7198c2ecf20Sopenharmony_ci perf_event__fprintf_aux(event, stdout); 7208c2ecf20Sopenharmony_ci return 0; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ciint machine__process_itrace_start_event(struct machine *machine __maybe_unused, 7248c2ecf20Sopenharmony_ci union perf_event *event) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci if (dump_trace) 7278c2ecf20Sopenharmony_ci perf_event__fprintf_itrace_start(event, stdout); 7288c2ecf20Sopenharmony_ci return 0; 7298c2ecf20Sopenharmony_ci} 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ciint machine__process_switch_event(struct machine *machine __maybe_unused, 7328c2ecf20Sopenharmony_ci union perf_event *event) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci if (dump_trace) 7358c2ecf20Sopenharmony_ci perf_event__fprintf_switch(event, stdout); 7368c2ecf20Sopenharmony_ci return 0; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic int machine__process_ksymbol_register(struct machine *machine, 7408c2ecf20Sopenharmony_ci union perf_event *event, 7418c2ecf20Sopenharmony_ci struct perf_sample *sample __maybe_unused) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct symbol *sym; 7448c2ecf20Sopenharmony_ci struct map *map = maps__find(&machine->kmaps, event->ksymbol.addr); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!map) { 7478c2ecf20Sopenharmony_ci struct dso *dso = dso__new(event->ksymbol.name); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (dso) { 7508c2ecf20Sopenharmony_ci dso->kernel = DSO_SPACE__KERNEL; 7518c2ecf20Sopenharmony_ci map = map__new2(0, dso); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (!dso || !map) { 7558c2ecf20Sopenharmony_ci dso__put(dso); 7568c2ecf20Sopenharmony_ci return -ENOMEM; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (event->ksymbol.ksym_type == PERF_RECORD_KSYMBOL_TYPE_OOL) { 7608c2ecf20Sopenharmony_ci map->dso->binary_type = DSO_BINARY_TYPE__OOL; 7618c2ecf20Sopenharmony_ci map->dso->data.file_size = event->ksymbol.len; 7628c2ecf20Sopenharmony_ci dso__set_loaded(map->dso); 7638c2ecf20Sopenharmony_ci } 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci map->start = event->ksymbol.addr; 7668c2ecf20Sopenharmony_ci map->end = map->start + event->ksymbol.len; 7678c2ecf20Sopenharmony_ci maps__insert(&machine->kmaps, map); 7688c2ecf20Sopenharmony_ci dso__set_loaded(dso); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (is_bpf_image(event->ksymbol.name)) { 7718c2ecf20Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__BPF_IMAGE; 7728c2ecf20Sopenharmony_ci dso__set_long_name(dso, "", false); 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci sym = symbol__new(map->map_ip(map, map->start), 7778c2ecf20Sopenharmony_ci event->ksymbol.len, 7788c2ecf20Sopenharmony_ci 0, 0, event->ksymbol.name); 7798c2ecf20Sopenharmony_ci if (!sym) 7808c2ecf20Sopenharmony_ci return -ENOMEM; 7818c2ecf20Sopenharmony_ci dso__insert_symbol(map->dso, sym); 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic int machine__process_ksymbol_unregister(struct machine *machine, 7868c2ecf20Sopenharmony_ci union perf_event *event, 7878c2ecf20Sopenharmony_ci struct perf_sample *sample __maybe_unused) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci struct symbol *sym; 7908c2ecf20Sopenharmony_ci struct map *map; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci map = maps__find(&machine->kmaps, event->ksymbol.addr); 7938c2ecf20Sopenharmony_ci if (!map) 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (map != machine->vmlinux_map) 7978c2ecf20Sopenharmony_ci maps__remove(&machine->kmaps, map); 7988c2ecf20Sopenharmony_ci else { 7998c2ecf20Sopenharmony_ci sym = dso__find_symbol(map->dso, map->map_ip(map, map->start)); 8008c2ecf20Sopenharmony_ci if (sym) 8018c2ecf20Sopenharmony_ci dso__delete_symbol(map->dso, sym); 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci return 0; 8058c2ecf20Sopenharmony_ci} 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ciint machine__process_ksymbol(struct machine *machine __maybe_unused, 8088c2ecf20Sopenharmony_ci union perf_event *event, 8098c2ecf20Sopenharmony_ci struct perf_sample *sample) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci if (dump_trace) 8128c2ecf20Sopenharmony_ci perf_event__fprintf_ksymbol(event, stdout); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (event->ksymbol.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER) 8158c2ecf20Sopenharmony_ci return machine__process_ksymbol_unregister(machine, event, 8168c2ecf20Sopenharmony_ci sample); 8178c2ecf20Sopenharmony_ci return machine__process_ksymbol_register(machine, event, sample); 8188c2ecf20Sopenharmony_ci} 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ciint machine__process_text_poke(struct machine *machine, union perf_event *event, 8218c2ecf20Sopenharmony_ci struct perf_sample *sample __maybe_unused) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct map *map = maps__find(&machine->kmaps, event->text_poke.addr); 8248c2ecf20Sopenharmony_ci u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci if (dump_trace) 8278c2ecf20Sopenharmony_ci perf_event__fprintf_text_poke(event, machine, stdout); 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (!event->text_poke.new_len) 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (cpumode != PERF_RECORD_MISC_KERNEL) { 8338c2ecf20Sopenharmony_ci pr_debug("%s: unsupported cpumode - ignoring\n", __func__); 8348c2ecf20Sopenharmony_ci return 0; 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci if (map && map->dso) { 8388c2ecf20Sopenharmony_ci u8 *new_bytes = event->text_poke.bytes + event->text_poke.old_len; 8398c2ecf20Sopenharmony_ci int ret; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* 8428c2ecf20Sopenharmony_ci * Kernel maps might be changed when loading symbols so loading 8438c2ecf20Sopenharmony_ci * must be done prior to using kernel maps. 8448c2ecf20Sopenharmony_ci */ 8458c2ecf20Sopenharmony_ci map__load(map); 8468c2ecf20Sopenharmony_ci ret = dso__data_write_cache_addr(map->dso, map, machine, 8478c2ecf20Sopenharmony_ci event->text_poke.addr, 8488c2ecf20Sopenharmony_ci new_bytes, 8498c2ecf20Sopenharmony_ci event->text_poke.new_len); 8508c2ecf20Sopenharmony_ci if (ret != event->text_poke.new_len) 8518c2ecf20Sopenharmony_ci pr_debug("Failed to write kernel text poke at %#" PRI_lx64 "\n", 8528c2ecf20Sopenharmony_ci event->text_poke.addr); 8538c2ecf20Sopenharmony_ci } else { 8548c2ecf20Sopenharmony_ci pr_debug("Failed to find kernel text poke address map for %#" PRI_lx64 "\n", 8558c2ecf20Sopenharmony_ci event->text_poke.addr); 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic struct map *machine__addnew_module_map(struct machine *machine, u64 start, 8628c2ecf20Sopenharmony_ci const char *filename) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci struct map *map = NULL; 8658c2ecf20Sopenharmony_ci struct kmod_path m; 8668c2ecf20Sopenharmony_ci struct dso *dso; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (kmod_path__parse_name(&m, filename)) 8698c2ecf20Sopenharmony_ci return NULL; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci dso = machine__findnew_module_dso(machine, &m, filename); 8728c2ecf20Sopenharmony_ci if (dso == NULL) 8738c2ecf20Sopenharmony_ci goto out; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci map = map__new2(start, dso); 8768c2ecf20Sopenharmony_ci if (map == NULL) 8778c2ecf20Sopenharmony_ci goto out; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci maps__insert(&machine->kmaps, map); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* Put the map here because maps__insert alread got it */ 8828c2ecf20Sopenharmony_ci map__put(map); 8838c2ecf20Sopenharmony_ciout: 8848c2ecf20Sopenharmony_ci /* put the dso here, corresponding to machine__findnew_module_dso */ 8858c2ecf20Sopenharmony_ci dso__put(dso); 8868c2ecf20Sopenharmony_ci zfree(&m.name); 8878c2ecf20Sopenharmony_ci return map; 8888c2ecf20Sopenharmony_ci} 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cisize_t machines__fprintf_dsos(struct machines *machines, FILE *fp) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct rb_node *nd; 8938c2ecf20Sopenharmony_ci size_t ret = __dsos__fprintf(&machines->host.dsos.head, fp); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 8968c2ecf20Sopenharmony_ci struct machine *pos = rb_entry(nd, struct machine, rb_node); 8978c2ecf20Sopenharmony_ci ret += __dsos__fprintf(&pos->dsos.head, fp); 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return ret; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cisize_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, 9048c2ecf20Sopenharmony_ci bool (skip)(struct dso *dso, int parm), int parm) 9058c2ecf20Sopenharmony_ci{ 9068c2ecf20Sopenharmony_ci return __dsos__fprintf_buildid(&m->dsos.head, fp, skip, parm); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cisize_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, 9108c2ecf20Sopenharmony_ci bool (skip)(struct dso *dso, int parm), int parm) 9118c2ecf20Sopenharmony_ci{ 9128c2ecf20Sopenharmony_ci struct rb_node *nd; 9138c2ecf20Sopenharmony_ci size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 9168c2ecf20Sopenharmony_ci struct machine *pos = rb_entry(nd, struct machine, rb_node); 9178c2ecf20Sopenharmony_ci ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci return ret; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cisize_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci int i; 9258c2ecf20Sopenharmony_ci size_t printed = 0; 9268c2ecf20Sopenharmony_ci struct dso *kdso = machine__kernel_dso(machine); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (kdso->has_build_id) { 9298c2ecf20Sopenharmony_ci char filename[PATH_MAX]; 9308c2ecf20Sopenharmony_ci if (dso__build_id_filename(kdso, filename, sizeof(filename), 9318c2ecf20Sopenharmony_ci false)) 9328c2ecf20Sopenharmony_ci printed += fprintf(fp, "[0] %s\n", filename); 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci for (i = 0; i < vmlinux_path__nr_entries; ++i) 9368c2ecf20Sopenharmony_ci printed += fprintf(fp, "[%d] %s\n", 9378c2ecf20Sopenharmony_ci i + kdso->has_build_id, vmlinux_path[i]); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return printed; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cisize_t machine__fprintf(struct machine *machine, FILE *fp) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci struct rb_node *nd; 9458c2ecf20Sopenharmony_ci size_t ret; 9468c2ecf20Sopenharmony_ci int i; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 9498c2ecf20Sopenharmony_ci struct threads *threads = &machine->threads[i]; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci down_read(&threads->lock); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci ret = fprintf(fp, "Threads: %u\n", threads->nr); 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci for (nd = rb_first_cached(&threads->entries); nd; 9568c2ecf20Sopenharmony_ci nd = rb_next(nd)) { 9578c2ecf20Sopenharmony_ci struct thread *pos = rb_entry(nd, struct thread, rb_node); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci ret += thread__fprintf(pos, fp); 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci up_read(&threads->lock); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci return ret; 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_cistatic struct dso *machine__get_kernel(struct machine *machine) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci const char *vmlinux_name = machine->mmap_name; 9708c2ecf20Sopenharmony_ci struct dso *kernel; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (machine__is_host(machine)) { 9738c2ecf20Sopenharmony_ci if (symbol_conf.vmlinux_name) 9748c2ecf20Sopenharmony_ci vmlinux_name = symbol_conf.vmlinux_name; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci kernel = machine__findnew_kernel(machine, vmlinux_name, 9778c2ecf20Sopenharmony_ci "[kernel]", DSO_SPACE__KERNEL); 9788c2ecf20Sopenharmony_ci } else { 9798c2ecf20Sopenharmony_ci if (symbol_conf.default_guest_vmlinux_name) 9808c2ecf20Sopenharmony_ci vmlinux_name = symbol_conf.default_guest_vmlinux_name; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci kernel = machine__findnew_kernel(machine, vmlinux_name, 9838c2ecf20Sopenharmony_ci "[guest.kernel]", 9848c2ecf20Sopenharmony_ci DSO_SPACE__KERNEL_GUEST); 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci if (kernel != NULL && (!kernel->has_build_id)) 9888c2ecf20Sopenharmony_ci dso__read_running_kernel_build_id(kernel, machine); 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci return kernel; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_cistruct process_args { 9948c2ecf20Sopenharmony_ci u64 start; 9958c2ecf20Sopenharmony_ci}; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_civoid machine__get_kallsyms_filename(struct machine *machine, char *buf, 9988c2ecf20Sopenharmony_ci size_t bufsz) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci if (machine__is_default_guest(machine)) 10018c2ecf20Sopenharmony_ci scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms); 10028c2ecf20Sopenharmony_ci else 10038c2ecf20Sopenharmony_ci scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ciconst char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci/* Figure out the start address of kernel map from /proc/kallsyms. 10098c2ecf20Sopenharmony_ci * Returns the name of the start symbol in *symbol_name. Pass in NULL as 10108c2ecf20Sopenharmony_ci * symbol_name if it's not that important. 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_cistatic int machine__get_running_kernel_start(struct machine *machine, 10138c2ecf20Sopenharmony_ci const char **symbol_name, 10148c2ecf20Sopenharmony_ci u64 *start, u64 *end) 10158c2ecf20Sopenharmony_ci{ 10168c2ecf20Sopenharmony_ci char filename[PATH_MAX]; 10178c2ecf20Sopenharmony_ci int i, err = -1; 10188c2ecf20Sopenharmony_ci const char *name; 10198c2ecf20Sopenharmony_ci u64 addr = 0; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci machine__get_kallsyms_filename(machine, filename, PATH_MAX); 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci if (symbol__restricted_filename(filename, "/proc/kallsyms")) 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { 10278c2ecf20Sopenharmony_ci err = kallsyms__get_function_start(filename, name, &addr); 10288c2ecf20Sopenharmony_ci if (!err) 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci if (err) 10338c2ecf20Sopenharmony_ci return -1; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (symbol_name) 10368c2ecf20Sopenharmony_ci *symbol_name = name; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci *start = addr; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci err = kallsyms__get_function_start(filename, "_etext", &addr); 10418c2ecf20Sopenharmony_ci if (!err) 10428c2ecf20Sopenharmony_ci *end = addr; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci return 0; 10458c2ecf20Sopenharmony_ci} 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ciint machine__create_extra_kernel_map(struct machine *machine, 10488c2ecf20Sopenharmony_ci struct dso *kernel, 10498c2ecf20Sopenharmony_ci struct extra_kernel_map *xm) 10508c2ecf20Sopenharmony_ci{ 10518c2ecf20Sopenharmony_ci struct kmap *kmap; 10528c2ecf20Sopenharmony_ci struct map *map; 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci map = map__new2(xm->start, kernel); 10558c2ecf20Sopenharmony_ci if (!map) 10568c2ecf20Sopenharmony_ci return -1; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci map->end = xm->end; 10598c2ecf20Sopenharmony_ci map->pgoff = xm->pgoff; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci kmap = map__kmap(map); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci strlcpy(kmap->name, xm->name, KMAP_NAME_LEN); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci maps__insert(&machine->kmaps, map); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci pr_debug2("Added extra kernel map %s %" PRIx64 "-%" PRIx64 "\n", 10688c2ecf20Sopenharmony_ci kmap->name, map->start, map->end); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci map__put(map); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci return 0; 10738c2ecf20Sopenharmony_ci} 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_cistatic u64 find_entry_trampoline(struct dso *dso) 10768c2ecf20Sopenharmony_ci{ 10778c2ecf20Sopenharmony_ci /* Duplicates are removed so lookup all aliases */ 10788c2ecf20Sopenharmony_ci const char *syms[] = { 10798c2ecf20Sopenharmony_ci "_entry_trampoline", 10808c2ecf20Sopenharmony_ci "__entry_trampoline_start", 10818c2ecf20Sopenharmony_ci "entry_SYSCALL_64_trampoline", 10828c2ecf20Sopenharmony_ci }; 10838c2ecf20Sopenharmony_ci struct symbol *sym = dso__first_symbol(dso); 10848c2ecf20Sopenharmony_ci unsigned int i; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci for (; sym; sym = dso__next_symbol(sym)) { 10878c2ecf20Sopenharmony_ci if (sym->binding != STB_GLOBAL) 10888c2ecf20Sopenharmony_ci continue; 10898c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(syms); i++) { 10908c2ecf20Sopenharmony_ci if (!strcmp(sym->name, syms[i])) 10918c2ecf20Sopenharmony_ci return sym->start; 10928c2ecf20Sopenharmony_ci } 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci} 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci/* 10998c2ecf20Sopenharmony_ci * These values can be used for kernels that do not have symbols for the entry 11008c2ecf20Sopenharmony_ci * trampolines in kallsyms. 11018c2ecf20Sopenharmony_ci */ 11028c2ecf20Sopenharmony_ci#define X86_64_CPU_ENTRY_AREA_PER_CPU 0xfffffe0000000000ULL 11038c2ecf20Sopenharmony_ci#define X86_64_CPU_ENTRY_AREA_SIZE 0x2c000 11048c2ecf20Sopenharmony_ci#define X86_64_ENTRY_TRAMPOLINE 0x6000 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci/* Map x86_64 PTI entry trampolines */ 11078c2ecf20Sopenharmony_ciint machine__map_x86_64_entry_trampolines(struct machine *machine, 11088c2ecf20Sopenharmony_ci struct dso *kernel) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct maps *kmaps = &machine->kmaps; 11118c2ecf20Sopenharmony_ci int nr_cpus_avail, cpu; 11128c2ecf20Sopenharmony_ci bool found = false; 11138c2ecf20Sopenharmony_ci struct map *map; 11148c2ecf20Sopenharmony_ci u64 pgoff; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* 11178c2ecf20Sopenharmony_ci * In the vmlinux case, pgoff is a virtual address which must now be 11188c2ecf20Sopenharmony_ci * mapped to a vmlinux offset. 11198c2ecf20Sopenharmony_ci */ 11208c2ecf20Sopenharmony_ci maps__for_each_entry(kmaps, map) { 11218c2ecf20Sopenharmony_ci struct kmap *kmap = __map__kmap(map); 11228c2ecf20Sopenharmony_ci struct map *dest_map; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci if (!kmap || !is_entry_trampoline(kmap->name)) 11258c2ecf20Sopenharmony_ci continue; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci dest_map = maps__find(kmaps, map->pgoff); 11288c2ecf20Sopenharmony_ci if (dest_map != map) 11298c2ecf20Sopenharmony_ci map->pgoff = dest_map->map_ip(dest_map, map->pgoff); 11308c2ecf20Sopenharmony_ci found = true; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci if (found || machine->trampolines_mapped) 11338c2ecf20Sopenharmony_ci return 0; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci pgoff = find_entry_trampoline(kernel); 11368c2ecf20Sopenharmony_ci if (!pgoff) 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci nr_cpus_avail = machine__nr_cpus_avail(machine); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci /* Add a 1 page map for each CPU's entry trampoline */ 11428c2ecf20Sopenharmony_ci for (cpu = 0; cpu < nr_cpus_avail; cpu++) { 11438c2ecf20Sopenharmony_ci u64 va = X86_64_CPU_ENTRY_AREA_PER_CPU + 11448c2ecf20Sopenharmony_ci cpu * X86_64_CPU_ENTRY_AREA_SIZE + 11458c2ecf20Sopenharmony_ci X86_64_ENTRY_TRAMPOLINE; 11468c2ecf20Sopenharmony_ci struct extra_kernel_map xm = { 11478c2ecf20Sopenharmony_ci .start = va, 11488c2ecf20Sopenharmony_ci .end = va + page_size, 11498c2ecf20Sopenharmony_ci .pgoff = pgoff, 11508c2ecf20Sopenharmony_ci }; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci strlcpy(xm.name, ENTRY_TRAMPOLINE_NAME, KMAP_NAME_LEN); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (machine__create_extra_kernel_map(machine, kernel, &xm) < 0) 11558c2ecf20Sopenharmony_ci return -1; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci machine->trampolines_mapped = nr_cpus_avail; 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci return 0; 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ciint __weak machine__create_extra_kernel_maps(struct machine *machine __maybe_unused, 11648c2ecf20Sopenharmony_ci struct dso *kernel __maybe_unused) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci return 0; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_cistatic int 11708c2ecf20Sopenharmony_ci__machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci /* In case of renewal the kernel map, destroy previous one */ 11738c2ecf20Sopenharmony_ci machine__destroy_kernel_maps(machine); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci machine->vmlinux_map = map__new2(0, kernel); 11768c2ecf20Sopenharmony_ci if (machine->vmlinux_map == NULL) 11778c2ecf20Sopenharmony_ci return -1; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci machine->vmlinux_map->map_ip = machine->vmlinux_map->unmap_ip = identity__map_ip; 11808c2ecf20Sopenharmony_ci maps__insert(&machine->kmaps, machine->vmlinux_map); 11818c2ecf20Sopenharmony_ci return 0; 11828c2ecf20Sopenharmony_ci} 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_civoid machine__destroy_kernel_maps(struct machine *machine) 11858c2ecf20Sopenharmony_ci{ 11868c2ecf20Sopenharmony_ci struct kmap *kmap; 11878c2ecf20Sopenharmony_ci struct map *map = machine__kernel_map(machine); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci if (map == NULL) 11908c2ecf20Sopenharmony_ci return; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci kmap = map__kmap(map); 11938c2ecf20Sopenharmony_ci maps__remove(&machine->kmaps, map); 11948c2ecf20Sopenharmony_ci if (kmap && kmap->ref_reloc_sym) { 11958c2ecf20Sopenharmony_ci zfree((char **)&kmap->ref_reloc_sym->name); 11968c2ecf20Sopenharmony_ci zfree(&kmap->ref_reloc_sym); 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci map__zput(machine->vmlinux_map); 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ciint machines__create_guest_kernel_maps(struct machines *machines) 12038c2ecf20Sopenharmony_ci{ 12048c2ecf20Sopenharmony_ci int ret = 0; 12058c2ecf20Sopenharmony_ci struct dirent **namelist = NULL; 12068c2ecf20Sopenharmony_ci int i, items = 0; 12078c2ecf20Sopenharmony_ci char path[PATH_MAX]; 12088c2ecf20Sopenharmony_ci pid_t pid; 12098c2ecf20Sopenharmony_ci char *endp; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci if (symbol_conf.default_guest_vmlinux_name || 12128c2ecf20Sopenharmony_ci symbol_conf.default_guest_modules || 12138c2ecf20Sopenharmony_ci symbol_conf.default_guest_kallsyms) { 12148c2ecf20Sopenharmony_ci machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci if (symbol_conf.guestmount) { 12188c2ecf20Sopenharmony_ci items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 12198c2ecf20Sopenharmony_ci if (items <= 0) 12208c2ecf20Sopenharmony_ci return -ENOENT; 12218c2ecf20Sopenharmony_ci for (i = 0; i < items; i++) { 12228c2ecf20Sopenharmony_ci if (!isdigit(namelist[i]->d_name[0])) { 12238c2ecf20Sopenharmony_ci /* Filter out . and .. */ 12248c2ecf20Sopenharmony_ci continue; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); 12278c2ecf20Sopenharmony_ci if ((*endp != '\0') || 12288c2ecf20Sopenharmony_ci (endp == namelist[i]->d_name) || 12298c2ecf20Sopenharmony_ci (errno == ERANGE)) { 12308c2ecf20Sopenharmony_ci pr_debug("invalid directory (%s). Skipping.\n", 12318c2ecf20Sopenharmony_ci namelist[i]->d_name); 12328c2ecf20Sopenharmony_ci continue; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci sprintf(path, "%s/%s/proc/kallsyms", 12358c2ecf20Sopenharmony_ci symbol_conf.guestmount, 12368c2ecf20Sopenharmony_ci namelist[i]->d_name); 12378c2ecf20Sopenharmony_ci ret = access(path, R_OK); 12388c2ecf20Sopenharmony_ci if (ret) { 12398c2ecf20Sopenharmony_ci pr_debug("Can't access file %s\n", path); 12408c2ecf20Sopenharmony_ci goto failure; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci machines__create_kernel_maps(machines, pid); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_cifailure: 12458c2ecf20Sopenharmony_ci free(namelist); 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci return ret; 12498c2ecf20Sopenharmony_ci} 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_civoid machines__destroy_kernel_maps(struct machines *machines) 12528c2ecf20Sopenharmony_ci{ 12538c2ecf20Sopenharmony_ci struct rb_node *next = rb_first_cached(&machines->guests); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci machine__destroy_kernel_maps(&machines->host); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci while (next) { 12588c2ecf20Sopenharmony_ci struct machine *pos = rb_entry(next, struct machine, rb_node); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci next = rb_next(&pos->rb_node); 12618c2ecf20Sopenharmony_ci rb_erase_cached(&pos->rb_node, &machines->guests); 12628c2ecf20Sopenharmony_ci machine__delete(pos); 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci} 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ciint machines__create_kernel_maps(struct machines *machines, pid_t pid) 12678c2ecf20Sopenharmony_ci{ 12688c2ecf20Sopenharmony_ci struct machine *machine = machines__findnew(machines, pid); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (machine == NULL) 12718c2ecf20Sopenharmony_ci return -1; 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci return machine__create_kernel_maps(machine); 12748c2ecf20Sopenharmony_ci} 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ciint machine__load_kallsyms(struct machine *machine, const char *filename) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci struct map *map = machine__kernel_map(machine); 12798c2ecf20Sopenharmony_ci int ret = __dso__load_kallsyms(map->dso, filename, map, true); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (ret > 0) { 12828c2ecf20Sopenharmony_ci dso__set_loaded(map->dso); 12838c2ecf20Sopenharmony_ci /* 12848c2ecf20Sopenharmony_ci * Since /proc/kallsyms will have multiple sessions for the 12858c2ecf20Sopenharmony_ci * kernel, with modules between them, fixup the end of all 12868c2ecf20Sopenharmony_ci * sections. 12878c2ecf20Sopenharmony_ci */ 12888c2ecf20Sopenharmony_ci maps__fixup_end(&machine->kmaps); 12898c2ecf20Sopenharmony_ci } 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci return ret; 12928c2ecf20Sopenharmony_ci} 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ciint machine__load_vmlinux_path(struct machine *machine) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct map *map = machine__kernel_map(machine); 12978c2ecf20Sopenharmony_ci int ret = dso__load_vmlinux_path(map->dso, map); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (ret > 0) 13008c2ecf20Sopenharmony_ci dso__set_loaded(map->dso); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci return ret; 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_cistatic char *get_kernel_version(const char *root_dir) 13068c2ecf20Sopenharmony_ci{ 13078c2ecf20Sopenharmony_ci char version[PATH_MAX]; 13088c2ecf20Sopenharmony_ci FILE *file; 13098c2ecf20Sopenharmony_ci char *name, *tmp; 13108c2ecf20Sopenharmony_ci const char *prefix = "Linux version "; 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci sprintf(version, "%s/proc/version", root_dir); 13138c2ecf20Sopenharmony_ci file = fopen(version, "r"); 13148c2ecf20Sopenharmony_ci if (!file) 13158c2ecf20Sopenharmony_ci return NULL; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci tmp = fgets(version, sizeof(version), file); 13188c2ecf20Sopenharmony_ci fclose(file); 13198c2ecf20Sopenharmony_ci if (!tmp) 13208c2ecf20Sopenharmony_ci return NULL; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci name = strstr(version, prefix); 13238c2ecf20Sopenharmony_ci if (!name) 13248c2ecf20Sopenharmony_ci return NULL; 13258c2ecf20Sopenharmony_ci name += strlen(prefix); 13268c2ecf20Sopenharmony_ci tmp = strchr(name, ' '); 13278c2ecf20Sopenharmony_ci if (tmp) 13288c2ecf20Sopenharmony_ci *tmp = '\0'; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci return strdup(name); 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_cistatic bool is_kmod_dso(struct dso *dso) 13348c2ecf20Sopenharmony_ci{ 13358c2ecf20Sopenharmony_ci return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 13368c2ecf20Sopenharmony_ci dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE; 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic int maps__set_module_path(struct maps *maps, const char *path, struct kmod_path *m) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci char *long_name; 13428c2ecf20Sopenharmony_ci struct map *map = maps__find_by_name(maps, m->name); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci if (map == NULL) 13458c2ecf20Sopenharmony_ci return 0; 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci long_name = strdup(path); 13488c2ecf20Sopenharmony_ci if (long_name == NULL) 13498c2ecf20Sopenharmony_ci return -ENOMEM; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci dso__set_long_name(map->dso, long_name, true); 13528c2ecf20Sopenharmony_ci dso__kernel_module_get_build_id(map->dso, ""); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci /* 13558c2ecf20Sopenharmony_ci * Full name could reveal us kmod compression, so 13568c2ecf20Sopenharmony_ci * we need to update the symtab_type if needed. 13578c2ecf20Sopenharmony_ci */ 13588c2ecf20Sopenharmony_ci if (m->comp && is_kmod_dso(map->dso)) { 13598c2ecf20Sopenharmony_ci map->dso->symtab_type++; 13608c2ecf20Sopenharmony_ci map->dso->comp = m->comp; 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci return 0; 13648c2ecf20Sopenharmony_ci} 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_cistatic int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, int depth) 13678c2ecf20Sopenharmony_ci{ 13688c2ecf20Sopenharmony_ci struct dirent *dent; 13698c2ecf20Sopenharmony_ci DIR *dir = opendir(dir_name); 13708c2ecf20Sopenharmony_ci int ret = 0; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (!dir) { 13738c2ecf20Sopenharmony_ci pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 13748c2ecf20Sopenharmony_ci return -1; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci while ((dent = readdir(dir)) != NULL) { 13788c2ecf20Sopenharmony_ci char path[PATH_MAX]; 13798c2ecf20Sopenharmony_ci struct stat st; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci /*sshfs might return bad dent->d_type, so we have to stat*/ 13828c2ecf20Sopenharmony_ci snprintf(path, sizeof(path), "%s/%s", dir_name, dent->d_name); 13838c2ecf20Sopenharmony_ci if (stat(path, &st)) 13848c2ecf20Sopenharmony_ci continue; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (S_ISDIR(st.st_mode)) { 13878c2ecf20Sopenharmony_ci if (!strcmp(dent->d_name, ".") || 13888c2ecf20Sopenharmony_ci !strcmp(dent->d_name, "..")) 13898c2ecf20Sopenharmony_ci continue; 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci /* Do not follow top-level source and build symlinks */ 13928c2ecf20Sopenharmony_ci if (depth == 0) { 13938c2ecf20Sopenharmony_ci if (!strcmp(dent->d_name, "source") || 13948c2ecf20Sopenharmony_ci !strcmp(dent->d_name, "build")) 13958c2ecf20Sopenharmony_ci continue; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ci ret = maps__set_modules_path_dir(maps, path, depth + 1); 13998c2ecf20Sopenharmony_ci if (ret < 0) 14008c2ecf20Sopenharmony_ci goto out; 14018c2ecf20Sopenharmony_ci } else { 14028c2ecf20Sopenharmony_ci struct kmod_path m; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci ret = kmod_path__parse_name(&m, dent->d_name); 14058c2ecf20Sopenharmony_ci if (ret) 14068c2ecf20Sopenharmony_ci goto out; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if (m.kmod) 14098c2ecf20Sopenharmony_ci ret = maps__set_module_path(maps, path, &m); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci zfree(&m.name); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (ret) 14148c2ecf20Sopenharmony_ci goto out; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ciout: 14198c2ecf20Sopenharmony_ci closedir(dir); 14208c2ecf20Sopenharmony_ci return ret; 14218c2ecf20Sopenharmony_ci} 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_cistatic int machine__set_modules_path(struct machine *machine) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci char *version; 14268c2ecf20Sopenharmony_ci char modules_path[PATH_MAX]; 14278c2ecf20Sopenharmony_ci 14288c2ecf20Sopenharmony_ci version = get_kernel_version(machine->root_dir); 14298c2ecf20Sopenharmony_ci if (!version) 14308c2ecf20Sopenharmony_ci return -1; 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s", 14338c2ecf20Sopenharmony_ci machine->root_dir, version); 14348c2ecf20Sopenharmony_ci free(version); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci return maps__set_modules_path_dir(&machine->kmaps, modules_path, 0); 14378c2ecf20Sopenharmony_ci} 14388c2ecf20Sopenharmony_ciint __weak arch__fix_module_text_start(u64 *start __maybe_unused, 14398c2ecf20Sopenharmony_ci u64 *size __maybe_unused, 14408c2ecf20Sopenharmony_ci const char *name __maybe_unused) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci return 0; 14438c2ecf20Sopenharmony_ci} 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_cistatic int machine__create_module(void *arg, const char *name, u64 start, 14468c2ecf20Sopenharmony_ci u64 size) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci struct machine *machine = arg; 14498c2ecf20Sopenharmony_ci struct map *map; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (arch__fix_module_text_start(&start, &size, name) < 0) 14528c2ecf20Sopenharmony_ci return -1; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci map = machine__addnew_module_map(machine, start, name); 14558c2ecf20Sopenharmony_ci if (map == NULL) 14568c2ecf20Sopenharmony_ci return -1; 14578c2ecf20Sopenharmony_ci map->end = start + size; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci dso__kernel_module_get_build_id(map->dso, machine->root_dir); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci return 0; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic int machine__create_modules(struct machine *machine) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci const char *modules; 14678c2ecf20Sopenharmony_ci char path[PATH_MAX]; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci if (machine__is_default_guest(machine)) { 14708c2ecf20Sopenharmony_ci modules = symbol_conf.default_guest_modules; 14718c2ecf20Sopenharmony_ci } else { 14728c2ecf20Sopenharmony_ci snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir); 14738c2ecf20Sopenharmony_ci modules = path; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci if (symbol__restricted_filename(modules, "/proc/modules")) 14778c2ecf20Sopenharmony_ci return -1; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (modules__parse(modules, machine, machine__create_module)) 14808c2ecf20Sopenharmony_ci return -1; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci if (!machine__set_modules_path(machine)) 14838c2ecf20Sopenharmony_ci return 0; 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci pr_debug("Problems setting modules path maps, continuing anyway...\n"); 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci return 0; 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic void machine__set_kernel_mmap(struct machine *machine, 14918c2ecf20Sopenharmony_ci u64 start, u64 end) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci machine->vmlinux_map->start = start; 14948c2ecf20Sopenharmony_ci machine->vmlinux_map->end = end; 14958c2ecf20Sopenharmony_ci /* 14968c2ecf20Sopenharmony_ci * Be a bit paranoid here, some perf.data file came with 14978c2ecf20Sopenharmony_ci * a zero sized synthesized MMAP event for the kernel. 14988c2ecf20Sopenharmony_ci */ 14998c2ecf20Sopenharmony_ci if (start == 0 && end == 0) 15008c2ecf20Sopenharmony_ci machine->vmlinux_map->end = ~0ULL; 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_cistatic void machine__update_kernel_mmap(struct machine *machine, 15048c2ecf20Sopenharmony_ci u64 start, u64 end) 15058c2ecf20Sopenharmony_ci{ 15068c2ecf20Sopenharmony_ci struct map *map = machine__kernel_map(machine); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci map__get(map); 15098c2ecf20Sopenharmony_ci maps__remove(&machine->kmaps, map); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci machine__set_kernel_mmap(machine, start, end); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci maps__insert(&machine->kmaps, map); 15148c2ecf20Sopenharmony_ci map__put(map); 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ciint machine__create_kernel_maps(struct machine *machine) 15188c2ecf20Sopenharmony_ci{ 15198c2ecf20Sopenharmony_ci struct dso *kernel = machine__get_kernel(machine); 15208c2ecf20Sopenharmony_ci const char *name = NULL; 15218c2ecf20Sopenharmony_ci struct map *map; 15228c2ecf20Sopenharmony_ci u64 start = 0, end = ~0ULL; 15238c2ecf20Sopenharmony_ci int ret; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci if (kernel == NULL) 15268c2ecf20Sopenharmony_ci return -1; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci ret = __machine__create_kernel_maps(machine, kernel); 15298c2ecf20Sopenharmony_ci if (ret < 0) 15308c2ecf20Sopenharmony_ci goto out_put; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 15338c2ecf20Sopenharmony_ci if (machine__is_host(machine)) 15348c2ecf20Sopenharmony_ci pr_debug("Problems creating module maps, " 15358c2ecf20Sopenharmony_ci "continuing anyway...\n"); 15368c2ecf20Sopenharmony_ci else 15378c2ecf20Sopenharmony_ci pr_debug("Problems creating module maps for guest %d, " 15388c2ecf20Sopenharmony_ci "continuing anyway...\n", machine->pid); 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (!machine__get_running_kernel_start(machine, &name, &start, &end)) { 15428c2ecf20Sopenharmony_ci if (name && 15438c2ecf20Sopenharmony_ci map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map, name, start)) { 15448c2ecf20Sopenharmony_ci machine__destroy_kernel_maps(machine); 15458c2ecf20Sopenharmony_ci ret = -1; 15468c2ecf20Sopenharmony_ci goto out_put; 15478c2ecf20Sopenharmony_ci } 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci /* 15508c2ecf20Sopenharmony_ci * we have a real start address now, so re-order the kmaps 15518c2ecf20Sopenharmony_ci * assume it's the last in the kmaps 15528c2ecf20Sopenharmony_ci */ 15538c2ecf20Sopenharmony_ci machine__update_kernel_mmap(machine, start, end); 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci if (machine__create_extra_kernel_maps(machine, kernel)) 15578c2ecf20Sopenharmony_ci pr_debug("Problems creating extra kernel maps, continuing anyway...\n"); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci if (end == ~0ULL) { 15608c2ecf20Sopenharmony_ci /* update end address of the kernel map using adjacent module address */ 15618c2ecf20Sopenharmony_ci map = map__next(machine__kernel_map(machine)); 15628c2ecf20Sopenharmony_ci if (map) 15638c2ecf20Sopenharmony_ci machine__set_kernel_mmap(machine, start, map->start); 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ciout_put: 15678c2ecf20Sopenharmony_ci dso__put(kernel); 15688c2ecf20Sopenharmony_ci return ret; 15698c2ecf20Sopenharmony_ci} 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_cistatic bool machine__uses_kcore(struct machine *machine) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci struct dso *dso; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci list_for_each_entry(dso, &machine->dsos.head, node) { 15768c2ecf20Sopenharmony_ci if (dso__is_kcore(dso)) 15778c2ecf20Sopenharmony_ci return true; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci return false; 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_cistatic bool perf_event__is_extra_kernel_mmap(struct machine *machine, 15848c2ecf20Sopenharmony_ci union perf_event *event) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci return machine__is(machine, "x86_64") && 15878c2ecf20Sopenharmony_ci is_entry_trampoline(event->mmap.filename); 15888c2ecf20Sopenharmony_ci} 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_cistatic int machine__process_extra_kernel_map(struct machine *machine, 15918c2ecf20Sopenharmony_ci union perf_event *event) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci struct dso *kernel = machine__kernel_dso(machine); 15948c2ecf20Sopenharmony_ci struct extra_kernel_map xm = { 15958c2ecf20Sopenharmony_ci .start = event->mmap.start, 15968c2ecf20Sopenharmony_ci .end = event->mmap.start + event->mmap.len, 15978c2ecf20Sopenharmony_ci .pgoff = event->mmap.pgoff, 15988c2ecf20Sopenharmony_ci }; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (kernel == NULL) 16018c2ecf20Sopenharmony_ci return -1; 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci return machine__create_extra_kernel_map(machine, kernel, &xm); 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_cistatic int machine__process_kernel_mmap_event(struct machine *machine, 16098c2ecf20Sopenharmony_ci union perf_event *event) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci struct map *map; 16128c2ecf20Sopenharmony_ci enum dso_space_type dso_space; 16138c2ecf20Sopenharmony_ci bool is_kernel_mmap; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci /* If we have maps from kcore then we do not need or want any others */ 16168c2ecf20Sopenharmony_ci if (machine__uses_kcore(machine)) 16178c2ecf20Sopenharmony_ci return 0; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci if (machine__is_host(machine)) 16208c2ecf20Sopenharmony_ci dso_space = DSO_SPACE__KERNEL; 16218c2ecf20Sopenharmony_ci else 16228c2ecf20Sopenharmony_ci dso_space = DSO_SPACE__KERNEL_GUEST; 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci is_kernel_mmap = memcmp(event->mmap.filename, 16258c2ecf20Sopenharmony_ci machine->mmap_name, 16268c2ecf20Sopenharmony_ci strlen(machine->mmap_name) - 1) == 0; 16278c2ecf20Sopenharmony_ci if (event->mmap.filename[0] == '/' || 16288c2ecf20Sopenharmony_ci (!is_kernel_mmap && event->mmap.filename[0] == '[')) { 16298c2ecf20Sopenharmony_ci map = machine__addnew_module_map(machine, event->mmap.start, 16308c2ecf20Sopenharmony_ci event->mmap.filename); 16318c2ecf20Sopenharmony_ci if (map == NULL) 16328c2ecf20Sopenharmony_ci goto out_problem; 16338c2ecf20Sopenharmony_ci 16348c2ecf20Sopenharmony_ci map->end = map->start + event->mmap.len; 16358c2ecf20Sopenharmony_ci } else if (is_kernel_mmap) { 16368c2ecf20Sopenharmony_ci const char *symbol_name = (event->mmap.filename + 16378c2ecf20Sopenharmony_ci strlen(machine->mmap_name)); 16388c2ecf20Sopenharmony_ci /* 16398c2ecf20Sopenharmony_ci * Should be there already, from the build-id table in 16408c2ecf20Sopenharmony_ci * the header. 16418c2ecf20Sopenharmony_ci */ 16428c2ecf20Sopenharmony_ci struct dso *kernel = NULL; 16438c2ecf20Sopenharmony_ci struct dso *dso; 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci down_read(&machine->dsos.lock); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci list_for_each_entry(dso, &machine->dsos.head, node) { 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* 16508c2ecf20Sopenharmony_ci * The cpumode passed to is_kernel_module is not the 16518c2ecf20Sopenharmony_ci * cpumode of *this* event. If we insist on passing 16528c2ecf20Sopenharmony_ci * correct cpumode to is_kernel_module, we should 16538c2ecf20Sopenharmony_ci * record the cpumode when we adding this dso to the 16548c2ecf20Sopenharmony_ci * linked list. 16558c2ecf20Sopenharmony_ci * 16568c2ecf20Sopenharmony_ci * However we don't really need passing correct 16578c2ecf20Sopenharmony_ci * cpumode. We know the correct cpumode must be kernel 16588c2ecf20Sopenharmony_ci * mode (if not, we should not link it onto kernel_dsos 16598c2ecf20Sopenharmony_ci * list). 16608c2ecf20Sopenharmony_ci * 16618c2ecf20Sopenharmony_ci * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. 16628c2ecf20Sopenharmony_ci * is_kernel_module() treats it as a kernel cpumode. 16638c2ecf20Sopenharmony_ci */ 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci if (!dso->kernel || 16668c2ecf20Sopenharmony_ci is_kernel_module(dso->long_name, 16678c2ecf20Sopenharmony_ci PERF_RECORD_MISC_CPUMODE_UNKNOWN)) 16688c2ecf20Sopenharmony_ci continue; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci kernel = dso; 16728c2ecf20Sopenharmony_ci break; 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci up_read(&machine->dsos.lock); 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci if (kernel == NULL) 16788c2ecf20Sopenharmony_ci kernel = machine__findnew_dso(machine, machine->mmap_name); 16798c2ecf20Sopenharmony_ci if (kernel == NULL) 16808c2ecf20Sopenharmony_ci goto out_problem; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci kernel->kernel = dso_space; 16838c2ecf20Sopenharmony_ci if (__machine__create_kernel_maps(machine, kernel) < 0) { 16848c2ecf20Sopenharmony_ci dso__put(kernel); 16858c2ecf20Sopenharmony_ci goto out_problem; 16868c2ecf20Sopenharmony_ci } 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (strstr(kernel->long_name, "vmlinux")) 16898c2ecf20Sopenharmony_ci dso__set_short_name(kernel, "[kernel.vmlinux]", false); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci machine__update_kernel_mmap(machine, event->mmap.start, 16928c2ecf20Sopenharmony_ci event->mmap.start + event->mmap.len); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci /* 16958c2ecf20Sopenharmony_ci * Avoid using a zero address (kptr_restrict) for the ref reloc 16968c2ecf20Sopenharmony_ci * symbol. Effectively having zero here means that at record 16978c2ecf20Sopenharmony_ci * time /proc/sys/kernel/kptr_restrict was non zero. 16988c2ecf20Sopenharmony_ci */ 16998c2ecf20Sopenharmony_ci if (event->mmap.pgoff != 0) { 17008c2ecf20Sopenharmony_ci map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map, 17018c2ecf20Sopenharmony_ci symbol_name, 17028c2ecf20Sopenharmony_ci event->mmap.pgoff); 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (machine__is_default_guest(machine)) { 17068c2ecf20Sopenharmony_ci /* 17078c2ecf20Sopenharmony_ci * preload dso of guest kernel and modules 17088c2ecf20Sopenharmony_ci */ 17098c2ecf20Sopenharmony_ci dso__load(kernel, machine__kernel_map(machine)); 17108c2ecf20Sopenharmony_ci } 17118c2ecf20Sopenharmony_ci } else if (perf_event__is_extra_kernel_mmap(machine, event)) { 17128c2ecf20Sopenharmony_ci return machine__process_extra_kernel_map(machine, event); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci return 0; 17158c2ecf20Sopenharmony_ciout_problem: 17168c2ecf20Sopenharmony_ci return -1; 17178c2ecf20Sopenharmony_ci} 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ciint machine__process_mmap2_event(struct machine *machine, 17208c2ecf20Sopenharmony_ci union perf_event *event, 17218c2ecf20Sopenharmony_ci struct perf_sample *sample) 17228c2ecf20Sopenharmony_ci{ 17238c2ecf20Sopenharmony_ci struct thread *thread; 17248c2ecf20Sopenharmony_ci struct map *map; 17258c2ecf20Sopenharmony_ci struct dso_id dso_id = { 17268c2ecf20Sopenharmony_ci .maj = event->mmap2.maj, 17278c2ecf20Sopenharmony_ci .min = event->mmap2.min, 17288c2ecf20Sopenharmony_ci .ino = event->mmap2.ino, 17298c2ecf20Sopenharmony_ci .ino_generation = event->mmap2.ino_generation, 17308c2ecf20Sopenharmony_ci }; 17318c2ecf20Sopenharmony_ci int ret = 0; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci if (dump_trace) 17348c2ecf20Sopenharmony_ci perf_event__fprintf_mmap2(event, stdout); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 17378c2ecf20Sopenharmony_ci sample->cpumode == PERF_RECORD_MISC_KERNEL) { 17388c2ecf20Sopenharmony_ci ret = machine__process_kernel_mmap_event(machine, event); 17398c2ecf20Sopenharmony_ci if (ret < 0) 17408c2ecf20Sopenharmony_ci goto out_problem; 17418c2ecf20Sopenharmony_ci return 0; 17428c2ecf20Sopenharmony_ci } 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, event->mmap2.pid, 17458c2ecf20Sopenharmony_ci event->mmap2.tid); 17468c2ecf20Sopenharmony_ci if (thread == NULL) 17478c2ecf20Sopenharmony_ci goto out_problem; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci map = map__new(machine, event->mmap2.start, 17508c2ecf20Sopenharmony_ci event->mmap2.len, event->mmap2.pgoff, 17518c2ecf20Sopenharmony_ci &dso_id, event->mmap2.prot, 17528c2ecf20Sopenharmony_ci event->mmap2.flags, 17538c2ecf20Sopenharmony_ci event->mmap2.filename, thread); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci if (map == NULL) 17568c2ecf20Sopenharmony_ci goto out_problem_map; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci ret = thread__insert_map(thread, map); 17598c2ecf20Sopenharmony_ci if (ret) 17608c2ecf20Sopenharmony_ci goto out_problem_insert; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci thread__put(thread); 17638c2ecf20Sopenharmony_ci map__put(map); 17648c2ecf20Sopenharmony_ci return 0; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ciout_problem_insert: 17678c2ecf20Sopenharmony_ci map__put(map); 17688c2ecf20Sopenharmony_ciout_problem_map: 17698c2ecf20Sopenharmony_ci thread__put(thread); 17708c2ecf20Sopenharmony_ciout_problem: 17718c2ecf20Sopenharmony_ci dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n"); 17728c2ecf20Sopenharmony_ci return 0; 17738c2ecf20Sopenharmony_ci} 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ciint machine__process_mmap_event(struct machine *machine, union perf_event *event, 17768c2ecf20Sopenharmony_ci struct perf_sample *sample) 17778c2ecf20Sopenharmony_ci{ 17788c2ecf20Sopenharmony_ci struct thread *thread; 17798c2ecf20Sopenharmony_ci struct map *map; 17808c2ecf20Sopenharmony_ci u32 prot = 0; 17818c2ecf20Sopenharmony_ci int ret = 0; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (dump_trace) 17848c2ecf20Sopenharmony_ci perf_event__fprintf_mmap(event, stdout); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 17878c2ecf20Sopenharmony_ci sample->cpumode == PERF_RECORD_MISC_KERNEL) { 17888c2ecf20Sopenharmony_ci ret = machine__process_kernel_mmap_event(machine, event); 17898c2ecf20Sopenharmony_ci if (ret < 0) 17908c2ecf20Sopenharmony_ci goto out_problem; 17918c2ecf20Sopenharmony_ci return 0; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, event->mmap.pid, 17958c2ecf20Sopenharmony_ci event->mmap.tid); 17968c2ecf20Sopenharmony_ci if (thread == NULL) 17978c2ecf20Sopenharmony_ci goto out_problem; 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci if (!(event->header.misc & PERF_RECORD_MISC_MMAP_DATA)) 18008c2ecf20Sopenharmony_ci prot = PROT_EXEC; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci map = map__new(machine, event->mmap.start, 18038c2ecf20Sopenharmony_ci event->mmap.len, event->mmap.pgoff, 18048c2ecf20Sopenharmony_ci NULL, prot, 0, event->mmap.filename, thread); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci if (map == NULL) 18078c2ecf20Sopenharmony_ci goto out_problem_map; 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci ret = thread__insert_map(thread, map); 18108c2ecf20Sopenharmony_ci if (ret) 18118c2ecf20Sopenharmony_ci goto out_problem_insert; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci thread__put(thread); 18148c2ecf20Sopenharmony_ci map__put(map); 18158c2ecf20Sopenharmony_ci return 0; 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_ciout_problem_insert: 18188c2ecf20Sopenharmony_ci map__put(map); 18198c2ecf20Sopenharmony_ciout_problem_map: 18208c2ecf20Sopenharmony_ci thread__put(thread); 18218c2ecf20Sopenharmony_ciout_problem: 18228c2ecf20Sopenharmony_ci dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 18238c2ecf20Sopenharmony_ci return 0; 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_cistatic void __machine__remove_thread(struct machine *machine, struct thread *th, bool lock) 18278c2ecf20Sopenharmony_ci{ 18288c2ecf20Sopenharmony_ci struct threads *threads = machine__threads(machine, th->tid); 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci if (threads->last_match == th) 18318c2ecf20Sopenharmony_ci threads__set_last_match(threads, NULL); 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci if (lock) 18348c2ecf20Sopenharmony_ci down_write(&threads->lock); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci BUG_ON(refcount_read(&th->refcnt) == 0); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci rb_erase_cached(&th->rb_node, &threads->entries); 18398c2ecf20Sopenharmony_ci RB_CLEAR_NODE(&th->rb_node); 18408c2ecf20Sopenharmony_ci --threads->nr; 18418c2ecf20Sopenharmony_ci /* 18428c2ecf20Sopenharmony_ci * Move it first to the dead_threads list, then drop the reference, 18438c2ecf20Sopenharmony_ci * if this is the last reference, then the thread__delete destructor 18448c2ecf20Sopenharmony_ci * will be called and we will remove it from the dead_threads list. 18458c2ecf20Sopenharmony_ci */ 18468c2ecf20Sopenharmony_ci list_add_tail(&th->node, &threads->dead); 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci /* 18498c2ecf20Sopenharmony_ci * We need to do the put here because if this is the last refcount, 18508c2ecf20Sopenharmony_ci * then we will be touching the threads->dead head when removing the 18518c2ecf20Sopenharmony_ci * thread. 18528c2ecf20Sopenharmony_ci */ 18538c2ecf20Sopenharmony_ci thread__put(th); 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci if (lock) 18568c2ecf20Sopenharmony_ci up_write(&threads->lock); 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_civoid machine__remove_thread(struct machine *machine, struct thread *th) 18608c2ecf20Sopenharmony_ci{ 18618c2ecf20Sopenharmony_ci return __machine__remove_thread(machine, th, true); 18628c2ecf20Sopenharmony_ci} 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ciint machine__process_fork_event(struct machine *machine, union perf_event *event, 18658c2ecf20Sopenharmony_ci struct perf_sample *sample) 18668c2ecf20Sopenharmony_ci{ 18678c2ecf20Sopenharmony_ci struct thread *thread = machine__find_thread(machine, 18688c2ecf20Sopenharmony_ci event->fork.pid, 18698c2ecf20Sopenharmony_ci event->fork.tid); 18708c2ecf20Sopenharmony_ci struct thread *parent = machine__findnew_thread(machine, 18718c2ecf20Sopenharmony_ci event->fork.ppid, 18728c2ecf20Sopenharmony_ci event->fork.ptid); 18738c2ecf20Sopenharmony_ci bool do_maps_clone = true; 18748c2ecf20Sopenharmony_ci int err = 0; 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci if (dump_trace) 18778c2ecf20Sopenharmony_ci perf_event__fprintf_task(event, stdout); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci /* 18808c2ecf20Sopenharmony_ci * There may be an existing thread that is not actually the parent, 18818c2ecf20Sopenharmony_ci * either because we are processing events out of order, or because the 18828c2ecf20Sopenharmony_ci * (fork) event that would have removed the thread was lost. Assume the 18838c2ecf20Sopenharmony_ci * latter case and continue on as best we can. 18848c2ecf20Sopenharmony_ci */ 18858c2ecf20Sopenharmony_ci if (parent->pid_ != (pid_t)event->fork.ppid) { 18868c2ecf20Sopenharmony_ci dump_printf("removing erroneous parent thread %d/%d\n", 18878c2ecf20Sopenharmony_ci parent->pid_, parent->tid); 18888c2ecf20Sopenharmony_ci machine__remove_thread(machine, parent); 18898c2ecf20Sopenharmony_ci thread__put(parent); 18908c2ecf20Sopenharmony_ci parent = machine__findnew_thread(machine, event->fork.ppid, 18918c2ecf20Sopenharmony_ci event->fork.ptid); 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci /* if a thread currently exists for the thread id remove it */ 18958c2ecf20Sopenharmony_ci if (thread != NULL) { 18968c2ecf20Sopenharmony_ci machine__remove_thread(machine, thread); 18978c2ecf20Sopenharmony_ci thread__put(thread); 18988c2ecf20Sopenharmony_ci } 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, event->fork.pid, 19018c2ecf20Sopenharmony_ci event->fork.tid); 19028c2ecf20Sopenharmony_ci /* 19038c2ecf20Sopenharmony_ci * When synthesizing FORK events, we are trying to create thread 19048c2ecf20Sopenharmony_ci * objects for the already running tasks on the machine. 19058c2ecf20Sopenharmony_ci * 19068c2ecf20Sopenharmony_ci * Normally, for a kernel FORK event, we want to clone the parent's 19078c2ecf20Sopenharmony_ci * maps because that is what the kernel just did. 19088c2ecf20Sopenharmony_ci * 19098c2ecf20Sopenharmony_ci * But when synthesizing, this should not be done. If we do, we end up 19108c2ecf20Sopenharmony_ci * with overlapping maps as we process the sythesized MMAP2 events that 19118c2ecf20Sopenharmony_ci * get delivered shortly thereafter. 19128c2ecf20Sopenharmony_ci * 19138c2ecf20Sopenharmony_ci * Use the FORK event misc flags in an internal way to signal this 19148c2ecf20Sopenharmony_ci * situation, so we can elide the map clone when appropriate. 19158c2ecf20Sopenharmony_ci */ 19168c2ecf20Sopenharmony_ci if (event->fork.header.misc & PERF_RECORD_MISC_FORK_EXEC) 19178c2ecf20Sopenharmony_ci do_maps_clone = false; 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ci if (thread == NULL || parent == NULL || 19208c2ecf20Sopenharmony_ci thread__fork(thread, parent, sample->time, do_maps_clone) < 0) { 19218c2ecf20Sopenharmony_ci dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 19228c2ecf20Sopenharmony_ci err = -1; 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci thread__put(thread); 19258c2ecf20Sopenharmony_ci thread__put(parent); 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci return err; 19288c2ecf20Sopenharmony_ci} 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ciint machine__process_exit_event(struct machine *machine, union perf_event *event, 19318c2ecf20Sopenharmony_ci struct perf_sample *sample __maybe_unused) 19328c2ecf20Sopenharmony_ci{ 19338c2ecf20Sopenharmony_ci struct thread *thread = machine__find_thread(machine, 19348c2ecf20Sopenharmony_ci event->fork.pid, 19358c2ecf20Sopenharmony_ci event->fork.tid); 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci if (dump_trace) 19388c2ecf20Sopenharmony_ci perf_event__fprintf_task(event, stdout); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci if (thread != NULL) { 19418c2ecf20Sopenharmony_ci thread__exited(thread); 19428c2ecf20Sopenharmony_ci thread__put(thread); 19438c2ecf20Sopenharmony_ci } 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci return 0; 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ciint machine__process_event(struct machine *machine, union perf_event *event, 19498c2ecf20Sopenharmony_ci struct perf_sample *sample) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci int ret; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci switch (event->header.type) { 19548c2ecf20Sopenharmony_ci case PERF_RECORD_COMM: 19558c2ecf20Sopenharmony_ci ret = machine__process_comm_event(machine, event, sample); break; 19568c2ecf20Sopenharmony_ci case PERF_RECORD_MMAP: 19578c2ecf20Sopenharmony_ci ret = machine__process_mmap_event(machine, event, sample); break; 19588c2ecf20Sopenharmony_ci case PERF_RECORD_NAMESPACES: 19598c2ecf20Sopenharmony_ci ret = machine__process_namespaces_event(machine, event, sample); break; 19608c2ecf20Sopenharmony_ci case PERF_RECORD_CGROUP: 19618c2ecf20Sopenharmony_ci ret = machine__process_cgroup_event(machine, event, sample); break; 19628c2ecf20Sopenharmony_ci case PERF_RECORD_MMAP2: 19638c2ecf20Sopenharmony_ci ret = machine__process_mmap2_event(machine, event, sample); break; 19648c2ecf20Sopenharmony_ci case PERF_RECORD_FORK: 19658c2ecf20Sopenharmony_ci ret = machine__process_fork_event(machine, event, sample); break; 19668c2ecf20Sopenharmony_ci case PERF_RECORD_EXIT: 19678c2ecf20Sopenharmony_ci ret = machine__process_exit_event(machine, event, sample); break; 19688c2ecf20Sopenharmony_ci case PERF_RECORD_LOST: 19698c2ecf20Sopenharmony_ci ret = machine__process_lost_event(machine, event, sample); break; 19708c2ecf20Sopenharmony_ci case PERF_RECORD_AUX: 19718c2ecf20Sopenharmony_ci ret = machine__process_aux_event(machine, event); break; 19728c2ecf20Sopenharmony_ci case PERF_RECORD_ITRACE_START: 19738c2ecf20Sopenharmony_ci ret = machine__process_itrace_start_event(machine, event); break; 19748c2ecf20Sopenharmony_ci case PERF_RECORD_LOST_SAMPLES: 19758c2ecf20Sopenharmony_ci ret = machine__process_lost_samples_event(machine, event, sample); break; 19768c2ecf20Sopenharmony_ci case PERF_RECORD_SWITCH: 19778c2ecf20Sopenharmony_ci case PERF_RECORD_SWITCH_CPU_WIDE: 19788c2ecf20Sopenharmony_ci ret = machine__process_switch_event(machine, event); break; 19798c2ecf20Sopenharmony_ci case PERF_RECORD_KSYMBOL: 19808c2ecf20Sopenharmony_ci ret = machine__process_ksymbol(machine, event, sample); break; 19818c2ecf20Sopenharmony_ci case PERF_RECORD_BPF_EVENT: 19828c2ecf20Sopenharmony_ci ret = machine__process_bpf(machine, event, sample); break; 19838c2ecf20Sopenharmony_ci case PERF_RECORD_TEXT_POKE: 19848c2ecf20Sopenharmony_ci ret = machine__process_text_poke(machine, event, sample); break; 19858c2ecf20Sopenharmony_ci default: 19868c2ecf20Sopenharmony_ci ret = -1; 19878c2ecf20Sopenharmony_ci break; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci return ret; 19918c2ecf20Sopenharmony_ci} 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_cistatic bool symbol__match_regex(struct symbol *sym, regex_t *regex) 19948c2ecf20Sopenharmony_ci{ 19958c2ecf20Sopenharmony_ci if (!regexec(regex, sym->name, 0, NULL, 0)) 19968c2ecf20Sopenharmony_ci return 1; 19978c2ecf20Sopenharmony_ci return 0; 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic void ip__resolve_ams(struct thread *thread, 20018c2ecf20Sopenharmony_ci struct addr_map_symbol *ams, 20028c2ecf20Sopenharmony_ci u64 ip) 20038c2ecf20Sopenharmony_ci{ 20048c2ecf20Sopenharmony_ci struct addr_location al; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci memset(&al, 0, sizeof(al)); 20078c2ecf20Sopenharmony_ci /* 20088c2ecf20Sopenharmony_ci * We cannot use the header.misc hint to determine whether a 20098c2ecf20Sopenharmony_ci * branch stack address is user, kernel, guest, hypervisor. 20108c2ecf20Sopenharmony_ci * Branches may straddle the kernel/user/hypervisor boundaries. 20118c2ecf20Sopenharmony_ci * Thus, we have to try consecutively until we find a match 20128c2ecf20Sopenharmony_ci * or else, the symbol is unknown 20138c2ecf20Sopenharmony_ci */ 20148c2ecf20Sopenharmony_ci thread__find_cpumode_addr_location(thread, ip, &al); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci ams->addr = ip; 20178c2ecf20Sopenharmony_ci ams->al_addr = al.addr; 20188c2ecf20Sopenharmony_ci ams->ms.maps = al.maps; 20198c2ecf20Sopenharmony_ci ams->ms.sym = al.sym; 20208c2ecf20Sopenharmony_ci ams->ms.map = al.map; 20218c2ecf20Sopenharmony_ci ams->phys_addr = 0; 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic void ip__resolve_data(struct thread *thread, 20258c2ecf20Sopenharmony_ci u8 m, struct addr_map_symbol *ams, 20268c2ecf20Sopenharmony_ci u64 addr, u64 phys_addr) 20278c2ecf20Sopenharmony_ci{ 20288c2ecf20Sopenharmony_ci struct addr_location al; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci memset(&al, 0, sizeof(al)); 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci thread__find_symbol(thread, m, addr, &al); 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci ams->addr = addr; 20358c2ecf20Sopenharmony_ci ams->al_addr = al.addr; 20368c2ecf20Sopenharmony_ci ams->ms.maps = al.maps; 20378c2ecf20Sopenharmony_ci ams->ms.sym = al.sym; 20388c2ecf20Sopenharmony_ci ams->ms.map = al.map; 20398c2ecf20Sopenharmony_ci ams->phys_addr = phys_addr; 20408c2ecf20Sopenharmony_ci} 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_cistruct mem_info *sample__resolve_mem(struct perf_sample *sample, 20438c2ecf20Sopenharmony_ci struct addr_location *al) 20448c2ecf20Sopenharmony_ci{ 20458c2ecf20Sopenharmony_ci struct mem_info *mi = mem_info__new(); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci if (!mi) 20488c2ecf20Sopenharmony_ci return NULL; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci ip__resolve_ams(al->thread, &mi->iaddr, sample->ip); 20518c2ecf20Sopenharmony_ci ip__resolve_data(al->thread, al->cpumode, &mi->daddr, 20528c2ecf20Sopenharmony_ci sample->addr, sample->phys_addr); 20538c2ecf20Sopenharmony_ci mi->data_src.val = sample->data_src; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci return mi; 20568c2ecf20Sopenharmony_ci} 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_cistatic char *callchain_srcline(struct map_symbol *ms, u64 ip) 20598c2ecf20Sopenharmony_ci{ 20608c2ecf20Sopenharmony_ci struct map *map = ms->map; 20618c2ecf20Sopenharmony_ci char *srcline = NULL; 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci if (!map || callchain_param.key == CCKEY_FUNCTION) 20648c2ecf20Sopenharmony_ci return srcline; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci srcline = srcline__tree_find(&map->dso->srclines, ip); 20678c2ecf20Sopenharmony_ci if (!srcline) { 20688c2ecf20Sopenharmony_ci bool show_sym = false; 20698c2ecf20Sopenharmony_ci bool show_addr = callchain_param.key == CCKEY_ADDRESS; 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci srcline = get_srcline(map->dso, map__rip_2objdump(map, ip), 20728c2ecf20Sopenharmony_ci ms->sym, show_sym, show_addr, ip); 20738c2ecf20Sopenharmony_ci srcline__tree_insert(&map->dso->srclines, ip, srcline); 20748c2ecf20Sopenharmony_ci } 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_ci return srcline; 20778c2ecf20Sopenharmony_ci} 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_cistruct iterations { 20808c2ecf20Sopenharmony_ci int nr_loop_iter; 20818c2ecf20Sopenharmony_ci u64 cycles; 20828c2ecf20Sopenharmony_ci}; 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_cistatic int add_callchain_ip(struct thread *thread, 20858c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 20868c2ecf20Sopenharmony_ci struct symbol **parent, 20878c2ecf20Sopenharmony_ci struct addr_location *root_al, 20888c2ecf20Sopenharmony_ci u8 *cpumode, 20898c2ecf20Sopenharmony_ci u64 ip, 20908c2ecf20Sopenharmony_ci bool branch, 20918c2ecf20Sopenharmony_ci struct branch_flags *flags, 20928c2ecf20Sopenharmony_ci struct iterations *iter, 20938c2ecf20Sopenharmony_ci u64 branch_from) 20948c2ecf20Sopenharmony_ci{ 20958c2ecf20Sopenharmony_ci struct map_symbol ms; 20968c2ecf20Sopenharmony_ci struct addr_location al; 20978c2ecf20Sopenharmony_ci int nr_loop_iter = 0; 20988c2ecf20Sopenharmony_ci u64 iter_cycles = 0; 20998c2ecf20Sopenharmony_ci const char *srcline = NULL; 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci al.filtered = 0; 21028c2ecf20Sopenharmony_ci al.sym = NULL; 21038c2ecf20Sopenharmony_ci al.srcline = NULL; 21048c2ecf20Sopenharmony_ci if (!cpumode) { 21058c2ecf20Sopenharmony_ci thread__find_cpumode_addr_location(thread, ip, &al); 21068c2ecf20Sopenharmony_ci } else { 21078c2ecf20Sopenharmony_ci if (ip >= PERF_CONTEXT_MAX) { 21088c2ecf20Sopenharmony_ci switch (ip) { 21098c2ecf20Sopenharmony_ci case PERF_CONTEXT_HV: 21108c2ecf20Sopenharmony_ci *cpumode = PERF_RECORD_MISC_HYPERVISOR; 21118c2ecf20Sopenharmony_ci break; 21128c2ecf20Sopenharmony_ci case PERF_CONTEXT_KERNEL: 21138c2ecf20Sopenharmony_ci *cpumode = PERF_RECORD_MISC_KERNEL; 21148c2ecf20Sopenharmony_ci break; 21158c2ecf20Sopenharmony_ci case PERF_CONTEXT_USER: 21168c2ecf20Sopenharmony_ci *cpumode = PERF_RECORD_MISC_USER; 21178c2ecf20Sopenharmony_ci break; 21188c2ecf20Sopenharmony_ci default: 21198c2ecf20Sopenharmony_ci pr_debug("invalid callchain context: " 21208c2ecf20Sopenharmony_ci "%"PRId64"\n", (s64) ip); 21218c2ecf20Sopenharmony_ci /* 21228c2ecf20Sopenharmony_ci * It seems the callchain is corrupted. 21238c2ecf20Sopenharmony_ci * Discard all. 21248c2ecf20Sopenharmony_ci */ 21258c2ecf20Sopenharmony_ci callchain_cursor_reset(cursor); 21268c2ecf20Sopenharmony_ci return 1; 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci return 0; 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci thread__find_symbol(thread, *cpumode, ip, &al); 21318c2ecf20Sopenharmony_ci } 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci if (al.sym != NULL) { 21348c2ecf20Sopenharmony_ci if (perf_hpp_list.parent && !*parent && 21358c2ecf20Sopenharmony_ci symbol__match_regex(al.sym, &parent_regex)) 21368c2ecf20Sopenharmony_ci *parent = al.sym; 21378c2ecf20Sopenharmony_ci else if (have_ignore_callees && root_al && 21388c2ecf20Sopenharmony_ci symbol__match_regex(al.sym, &ignore_callees_regex)) { 21398c2ecf20Sopenharmony_ci /* Treat this symbol as the root, 21408c2ecf20Sopenharmony_ci forgetting its callees. */ 21418c2ecf20Sopenharmony_ci *root_al = al; 21428c2ecf20Sopenharmony_ci callchain_cursor_reset(cursor); 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci if (symbol_conf.hide_unresolved && al.sym == NULL) 21478c2ecf20Sopenharmony_ci return 0; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci if (iter) { 21508c2ecf20Sopenharmony_ci nr_loop_iter = iter->nr_loop_iter; 21518c2ecf20Sopenharmony_ci iter_cycles = iter->cycles; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci ms.maps = al.maps; 21558c2ecf20Sopenharmony_ci ms.map = al.map; 21568c2ecf20Sopenharmony_ci ms.sym = al.sym; 21578c2ecf20Sopenharmony_ci srcline = callchain_srcline(&ms, al.addr); 21588c2ecf20Sopenharmony_ci return callchain_cursor_append(cursor, ip, &ms, 21598c2ecf20Sopenharmony_ci branch, flags, nr_loop_iter, 21608c2ecf20Sopenharmony_ci iter_cycles, branch_from, srcline); 21618c2ecf20Sopenharmony_ci} 21628c2ecf20Sopenharmony_ci 21638c2ecf20Sopenharmony_cistruct branch_info *sample__resolve_bstack(struct perf_sample *sample, 21648c2ecf20Sopenharmony_ci struct addr_location *al) 21658c2ecf20Sopenharmony_ci{ 21668c2ecf20Sopenharmony_ci unsigned int i; 21678c2ecf20Sopenharmony_ci const struct branch_stack *bs = sample->branch_stack; 21688c2ecf20Sopenharmony_ci struct branch_entry *entries = perf_sample__branch_entries(sample); 21698c2ecf20Sopenharmony_ci struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info)); 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci if (!bi) 21728c2ecf20Sopenharmony_ci return NULL; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci for (i = 0; i < bs->nr; i++) { 21758c2ecf20Sopenharmony_ci ip__resolve_ams(al->thread, &bi[i].to, entries[i].to); 21768c2ecf20Sopenharmony_ci ip__resolve_ams(al->thread, &bi[i].from, entries[i].from); 21778c2ecf20Sopenharmony_ci bi[i].flags = entries[i].flags; 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci return bi; 21808c2ecf20Sopenharmony_ci} 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_cistatic void save_iterations(struct iterations *iter, 21838c2ecf20Sopenharmony_ci struct branch_entry *be, int nr) 21848c2ecf20Sopenharmony_ci{ 21858c2ecf20Sopenharmony_ci int i; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci iter->nr_loop_iter++; 21888c2ecf20Sopenharmony_ci iter->cycles = 0; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) 21918c2ecf20Sopenharmony_ci iter->cycles += be[i].flags.cycles; 21928c2ecf20Sopenharmony_ci} 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci#define CHASHSZ 127 21958c2ecf20Sopenharmony_ci#define CHASHBITS 7 21968c2ecf20Sopenharmony_ci#define NO_ENTRY 0xff 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci#define PERF_MAX_BRANCH_DEPTH 127 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_ci/* Remove loops. */ 22018c2ecf20Sopenharmony_cistatic int remove_loops(struct branch_entry *l, int nr, 22028c2ecf20Sopenharmony_ci struct iterations *iter) 22038c2ecf20Sopenharmony_ci{ 22048c2ecf20Sopenharmony_ci int i, j, off; 22058c2ecf20Sopenharmony_ci unsigned char chash[CHASHSZ]; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci memset(chash, NO_ENTRY, sizeof(chash)); 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci BUG_ON(PERF_MAX_BRANCH_DEPTH > 255); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 22128c2ecf20Sopenharmony_ci int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci /* no collision handling for now */ 22158c2ecf20Sopenharmony_ci if (chash[h] == NO_ENTRY) { 22168c2ecf20Sopenharmony_ci chash[h] = i; 22178c2ecf20Sopenharmony_ci } else if (l[chash[h]].from == l[i].from) { 22188c2ecf20Sopenharmony_ci bool is_loop = true; 22198c2ecf20Sopenharmony_ci /* check if it is a real loop */ 22208c2ecf20Sopenharmony_ci off = 0; 22218c2ecf20Sopenharmony_ci for (j = chash[h]; j < i && i + off < nr; j++, off++) 22228c2ecf20Sopenharmony_ci if (l[j].from != l[i + off].from) { 22238c2ecf20Sopenharmony_ci is_loop = false; 22248c2ecf20Sopenharmony_ci break; 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci if (is_loop) { 22278c2ecf20Sopenharmony_ci j = nr - (i + off); 22288c2ecf20Sopenharmony_ci if (j > 0) { 22298c2ecf20Sopenharmony_ci save_iterations(iter + i + off, 22308c2ecf20Sopenharmony_ci l + i, off); 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci memmove(iter + i, iter + i + off, 22338c2ecf20Sopenharmony_ci j * sizeof(*iter)); 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci memmove(l + i, l + i + off, 22368c2ecf20Sopenharmony_ci j * sizeof(*l)); 22378c2ecf20Sopenharmony_ci } 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci nr -= off; 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci } 22438c2ecf20Sopenharmony_ci return nr; 22448c2ecf20Sopenharmony_ci} 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_cistatic int lbr_callchain_add_kernel_ip(struct thread *thread, 22478c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 22488c2ecf20Sopenharmony_ci struct perf_sample *sample, 22498c2ecf20Sopenharmony_ci struct symbol **parent, 22508c2ecf20Sopenharmony_ci struct addr_location *root_al, 22518c2ecf20Sopenharmony_ci u64 branch_from, 22528c2ecf20Sopenharmony_ci bool callee, int end) 22538c2ecf20Sopenharmony_ci{ 22548c2ecf20Sopenharmony_ci struct ip_callchain *chain = sample->callchain; 22558c2ecf20Sopenharmony_ci u8 cpumode = PERF_RECORD_MISC_USER; 22568c2ecf20Sopenharmony_ci int err, i; 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if (callee) { 22598c2ecf20Sopenharmony_ci for (i = 0; i < end + 1; i++) { 22608c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 22618c2ecf20Sopenharmony_ci root_al, &cpumode, chain->ips[i], 22628c2ecf20Sopenharmony_ci false, NULL, NULL, branch_from); 22638c2ecf20Sopenharmony_ci if (err) 22648c2ecf20Sopenharmony_ci return err; 22658c2ecf20Sopenharmony_ci } 22668c2ecf20Sopenharmony_ci return 0; 22678c2ecf20Sopenharmony_ci } 22688c2ecf20Sopenharmony_ci 22698c2ecf20Sopenharmony_ci for (i = end; i >= 0; i--) { 22708c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 22718c2ecf20Sopenharmony_ci root_al, &cpumode, chain->ips[i], 22728c2ecf20Sopenharmony_ci false, NULL, NULL, branch_from); 22738c2ecf20Sopenharmony_ci if (err) 22748c2ecf20Sopenharmony_ci return err; 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci return 0; 22788c2ecf20Sopenharmony_ci} 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_cistatic void save_lbr_cursor_node(struct thread *thread, 22818c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 22828c2ecf20Sopenharmony_ci int idx) 22838c2ecf20Sopenharmony_ci{ 22848c2ecf20Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread->lbr_stitch; 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci if (!lbr_stitch) 22878c2ecf20Sopenharmony_ci return; 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci if (cursor->pos == cursor->nr) { 22908c2ecf20Sopenharmony_ci lbr_stitch->prev_lbr_cursor[idx].valid = false; 22918c2ecf20Sopenharmony_ci return; 22928c2ecf20Sopenharmony_ci } 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci if (!cursor->curr) 22958c2ecf20Sopenharmony_ci cursor->curr = cursor->first; 22968c2ecf20Sopenharmony_ci else 22978c2ecf20Sopenharmony_ci cursor->curr = cursor->curr->next; 22988c2ecf20Sopenharmony_ci memcpy(&lbr_stitch->prev_lbr_cursor[idx], cursor->curr, 22998c2ecf20Sopenharmony_ci sizeof(struct callchain_cursor_node)); 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci lbr_stitch->prev_lbr_cursor[idx].valid = true; 23028c2ecf20Sopenharmony_ci cursor->pos++; 23038c2ecf20Sopenharmony_ci} 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_cistatic int lbr_callchain_add_lbr_ip(struct thread *thread, 23068c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 23078c2ecf20Sopenharmony_ci struct perf_sample *sample, 23088c2ecf20Sopenharmony_ci struct symbol **parent, 23098c2ecf20Sopenharmony_ci struct addr_location *root_al, 23108c2ecf20Sopenharmony_ci u64 *branch_from, 23118c2ecf20Sopenharmony_ci bool callee) 23128c2ecf20Sopenharmony_ci{ 23138c2ecf20Sopenharmony_ci struct branch_stack *lbr_stack = sample->branch_stack; 23148c2ecf20Sopenharmony_ci struct branch_entry *entries = perf_sample__branch_entries(sample); 23158c2ecf20Sopenharmony_ci u8 cpumode = PERF_RECORD_MISC_USER; 23168c2ecf20Sopenharmony_ci int lbr_nr = lbr_stack->nr; 23178c2ecf20Sopenharmony_ci struct branch_flags *flags; 23188c2ecf20Sopenharmony_ci int err, i; 23198c2ecf20Sopenharmony_ci u64 ip; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci /* 23228c2ecf20Sopenharmony_ci * The curr and pos are not used in writing session. They are cleared 23238c2ecf20Sopenharmony_ci * in callchain_cursor_commit() when the writing session is closed. 23248c2ecf20Sopenharmony_ci * Using curr and pos to track the current cursor node. 23258c2ecf20Sopenharmony_ci */ 23268c2ecf20Sopenharmony_ci if (thread->lbr_stitch) { 23278c2ecf20Sopenharmony_ci cursor->curr = NULL; 23288c2ecf20Sopenharmony_ci cursor->pos = cursor->nr; 23298c2ecf20Sopenharmony_ci if (cursor->nr) { 23308c2ecf20Sopenharmony_ci cursor->curr = cursor->first; 23318c2ecf20Sopenharmony_ci for (i = 0; i < (int)(cursor->nr - 1); i++) 23328c2ecf20Sopenharmony_ci cursor->curr = cursor->curr->next; 23338c2ecf20Sopenharmony_ci } 23348c2ecf20Sopenharmony_ci } 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci if (callee) { 23378c2ecf20Sopenharmony_ci /* Add LBR ip from first entries.to */ 23388c2ecf20Sopenharmony_ci ip = entries[0].to; 23398c2ecf20Sopenharmony_ci flags = &entries[0].flags; 23408c2ecf20Sopenharmony_ci *branch_from = entries[0].from; 23418c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 23428c2ecf20Sopenharmony_ci root_al, &cpumode, ip, 23438c2ecf20Sopenharmony_ci true, flags, NULL, 23448c2ecf20Sopenharmony_ci *branch_from); 23458c2ecf20Sopenharmony_ci if (err) 23468c2ecf20Sopenharmony_ci return err; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci /* 23498c2ecf20Sopenharmony_ci * The number of cursor node increases. 23508c2ecf20Sopenharmony_ci * Move the current cursor node. 23518c2ecf20Sopenharmony_ci * But does not need to save current cursor node for entry 0. 23528c2ecf20Sopenharmony_ci * It's impossible to stitch the whole LBRs of previous sample. 23538c2ecf20Sopenharmony_ci */ 23548c2ecf20Sopenharmony_ci if (thread->lbr_stitch && (cursor->pos != cursor->nr)) { 23558c2ecf20Sopenharmony_ci if (!cursor->curr) 23568c2ecf20Sopenharmony_ci cursor->curr = cursor->first; 23578c2ecf20Sopenharmony_ci else 23588c2ecf20Sopenharmony_ci cursor->curr = cursor->curr->next; 23598c2ecf20Sopenharmony_ci cursor->pos++; 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci /* Add LBR ip from entries.from one by one. */ 23638c2ecf20Sopenharmony_ci for (i = 0; i < lbr_nr; i++) { 23648c2ecf20Sopenharmony_ci ip = entries[i].from; 23658c2ecf20Sopenharmony_ci flags = &entries[i].flags; 23668c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 23678c2ecf20Sopenharmony_ci root_al, &cpumode, ip, 23688c2ecf20Sopenharmony_ci true, flags, NULL, 23698c2ecf20Sopenharmony_ci *branch_from); 23708c2ecf20Sopenharmony_ci if (err) 23718c2ecf20Sopenharmony_ci return err; 23728c2ecf20Sopenharmony_ci save_lbr_cursor_node(thread, cursor, i); 23738c2ecf20Sopenharmony_ci } 23748c2ecf20Sopenharmony_ci return 0; 23758c2ecf20Sopenharmony_ci } 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci /* Add LBR ip from entries.from one by one. */ 23788c2ecf20Sopenharmony_ci for (i = lbr_nr - 1; i >= 0; i--) { 23798c2ecf20Sopenharmony_ci ip = entries[i].from; 23808c2ecf20Sopenharmony_ci flags = &entries[i].flags; 23818c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 23828c2ecf20Sopenharmony_ci root_al, &cpumode, ip, 23838c2ecf20Sopenharmony_ci true, flags, NULL, 23848c2ecf20Sopenharmony_ci *branch_from); 23858c2ecf20Sopenharmony_ci if (err) 23868c2ecf20Sopenharmony_ci return err; 23878c2ecf20Sopenharmony_ci save_lbr_cursor_node(thread, cursor, i); 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci if (lbr_nr > 0) { 23918c2ecf20Sopenharmony_ci /* Add LBR ip from first entries.to */ 23928c2ecf20Sopenharmony_ci ip = entries[0].to; 23938c2ecf20Sopenharmony_ci flags = &entries[0].flags; 23948c2ecf20Sopenharmony_ci *branch_from = entries[0].from; 23958c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 23968c2ecf20Sopenharmony_ci root_al, &cpumode, ip, 23978c2ecf20Sopenharmony_ci true, flags, NULL, 23988c2ecf20Sopenharmony_ci *branch_from); 23998c2ecf20Sopenharmony_ci if (err) 24008c2ecf20Sopenharmony_ci return err; 24018c2ecf20Sopenharmony_ci } 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci return 0; 24048c2ecf20Sopenharmony_ci} 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_cistatic int lbr_callchain_add_stitched_lbr_ip(struct thread *thread, 24078c2ecf20Sopenharmony_ci struct callchain_cursor *cursor) 24088c2ecf20Sopenharmony_ci{ 24098c2ecf20Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread->lbr_stitch; 24108c2ecf20Sopenharmony_ci struct callchain_cursor_node *cnode; 24118c2ecf20Sopenharmony_ci struct stitch_list *stitch_node; 24128c2ecf20Sopenharmony_ci int err; 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci list_for_each_entry(stitch_node, &lbr_stitch->lists, node) { 24158c2ecf20Sopenharmony_ci cnode = &stitch_node->cursor; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci err = callchain_cursor_append(cursor, cnode->ip, 24188c2ecf20Sopenharmony_ci &cnode->ms, 24198c2ecf20Sopenharmony_ci cnode->branch, 24208c2ecf20Sopenharmony_ci &cnode->branch_flags, 24218c2ecf20Sopenharmony_ci cnode->nr_loop_iter, 24228c2ecf20Sopenharmony_ci cnode->iter_cycles, 24238c2ecf20Sopenharmony_ci cnode->branch_from, 24248c2ecf20Sopenharmony_ci cnode->srcline); 24258c2ecf20Sopenharmony_ci if (err) 24268c2ecf20Sopenharmony_ci return err; 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci return 0; 24298c2ecf20Sopenharmony_ci} 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_cistatic struct stitch_list *get_stitch_node(struct thread *thread) 24328c2ecf20Sopenharmony_ci{ 24338c2ecf20Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread->lbr_stitch; 24348c2ecf20Sopenharmony_ci struct stitch_list *stitch_node; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci if (!list_empty(&lbr_stitch->free_lists)) { 24378c2ecf20Sopenharmony_ci stitch_node = list_first_entry(&lbr_stitch->free_lists, 24388c2ecf20Sopenharmony_ci struct stitch_list, node); 24398c2ecf20Sopenharmony_ci list_del(&stitch_node->node); 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci return stitch_node; 24428c2ecf20Sopenharmony_ci } 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci return malloc(sizeof(struct stitch_list)); 24458c2ecf20Sopenharmony_ci} 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_cistatic bool has_stitched_lbr(struct thread *thread, 24488c2ecf20Sopenharmony_ci struct perf_sample *cur, 24498c2ecf20Sopenharmony_ci struct perf_sample *prev, 24508c2ecf20Sopenharmony_ci unsigned int max_lbr, 24518c2ecf20Sopenharmony_ci bool callee) 24528c2ecf20Sopenharmony_ci{ 24538c2ecf20Sopenharmony_ci struct branch_stack *cur_stack = cur->branch_stack; 24548c2ecf20Sopenharmony_ci struct branch_entry *cur_entries = perf_sample__branch_entries(cur); 24558c2ecf20Sopenharmony_ci struct branch_stack *prev_stack = prev->branch_stack; 24568c2ecf20Sopenharmony_ci struct branch_entry *prev_entries = perf_sample__branch_entries(prev); 24578c2ecf20Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread->lbr_stitch; 24588c2ecf20Sopenharmony_ci int i, j, nr_identical_branches = 0; 24598c2ecf20Sopenharmony_ci struct stitch_list *stitch_node; 24608c2ecf20Sopenharmony_ci u64 cur_base, distance; 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci if (!cur_stack || !prev_stack) 24638c2ecf20Sopenharmony_ci return false; 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci /* Find the physical index of the base-of-stack for current sample. */ 24668c2ecf20Sopenharmony_ci cur_base = max_lbr - cur_stack->nr + cur_stack->hw_idx + 1; 24678c2ecf20Sopenharmony_ci 24688c2ecf20Sopenharmony_ci distance = (prev_stack->hw_idx > cur_base) ? (prev_stack->hw_idx - cur_base) : 24698c2ecf20Sopenharmony_ci (max_lbr + prev_stack->hw_idx - cur_base); 24708c2ecf20Sopenharmony_ci /* Previous sample has shorter stack. Nothing can be stitched. */ 24718c2ecf20Sopenharmony_ci if (distance + 1 > prev_stack->nr) 24728c2ecf20Sopenharmony_ci return false; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci /* 24758c2ecf20Sopenharmony_ci * Check if there are identical LBRs between two samples. 24768c2ecf20Sopenharmony_ci * Identicall LBRs must have same from, to and flags values. Also, 24778c2ecf20Sopenharmony_ci * they have to be saved in the same LBR registers (same physical 24788c2ecf20Sopenharmony_ci * index). 24798c2ecf20Sopenharmony_ci * 24808c2ecf20Sopenharmony_ci * Starts from the base-of-stack of current sample. 24818c2ecf20Sopenharmony_ci */ 24828c2ecf20Sopenharmony_ci for (i = distance, j = cur_stack->nr - 1; (i >= 0) && (j >= 0); i--, j--) { 24838c2ecf20Sopenharmony_ci if ((prev_entries[i].from != cur_entries[j].from) || 24848c2ecf20Sopenharmony_ci (prev_entries[i].to != cur_entries[j].to) || 24858c2ecf20Sopenharmony_ci (prev_entries[i].flags.value != cur_entries[j].flags.value)) 24868c2ecf20Sopenharmony_ci break; 24878c2ecf20Sopenharmony_ci nr_identical_branches++; 24888c2ecf20Sopenharmony_ci } 24898c2ecf20Sopenharmony_ci 24908c2ecf20Sopenharmony_ci if (!nr_identical_branches) 24918c2ecf20Sopenharmony_ci return false; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci /* 24948c2ecf20Sopenharmony_ci * Save the LBRs between the base-of-stack of previous sample 24958c2ecf20Sopenharmony_ci * and the base-of-stack of current sample into lbr_stitch->lists. 24968c2ecf20Sopenharmony_ci * These LBRs will be stitched later. 24978c2ecf20Sopenharmony_ci */ 24988c2ecf20Sopenharmony_ci for (i = prev_stack->nr - 1; i > (int)distance; i--) { 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci if (!lbr_stitch->prev_lbr_cursor[i].valid) 25018c2ecf20Sopenharmony_ci continue; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_ci stitch_node = get_stitch_node(thread); 25048c2ecf20Sopenharmony_ci if (!stitch_node) 25058c2ecf20Sopenharmony_ci return false; 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci memcpy(&stitch_node->cursor, &lbr_stitch->prev_lbr_cursor[i], 25088c2ecf20Sopenharmony_ci sizeof(struct callchain_cursor_node)); 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci if (callee) 25118c2ecf20Sopenharmony_ci list_add(&stitch_node->node, &lbr_stitch->lists); 25128c2ecf20Sopenharmony_ci else 25138c2ecf20Sopenharmony_ci list_add_tail(&stitch_node->node, &lbr_stitch->lists); 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci return true; 25178c2ecf20Sopenharmony_ci} 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_cistatic bool alloc_lbr_stitch(struct thread *thread, unsigned int max_lbr) 25208c2ecf20Sopenharmony_ci{ 25218c2ecf20Sopenharmony_ci if (thread->lbr_stitch) 25228c2ecf20Sopenharmony_ci return true; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci thread->lbr_stitch = zalloc(sizeof(*thread->lbr_stitch)); 25258c2ecf20Sopenharmony_ci if (!thread->lbr_stitch) 25268c2ecf20Sopenharmony_ci goto err; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci thread->lbr_stitch->prev_lbr_cursor = calloc(max_lbr + 1, sizeof(struct callchain_cursor_node)); 25298c2ecf20Sopenharmony_ci if (!thread->lbr_stitch->prev_lbr_cursor) 25308c2ecf20Sopenharmony_ci goto free_lbr_stitch; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&thread->lbr_stitch->lists); 25338c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&thread->lbr_stitch->free_lists); 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci return true; 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_cifree_lbr_stitch: 25388c2ecf20Sopenharmony_ci zfree(&thread->lbr_stitch); 25398c2ecf20Sopenharmony_cierr: 25408c2ecf20Sopenharmony_ci pr_warning("Failed to allocate space for stitched LBRs. Disable LBR stitch\n"); 25418c2ecf20Sopenharmony_ci thread->lbr_stitch_enable = false; 25428c2ecf20Sopenharmony_ci return false; 25438c2ecf20Sopenharmony_ci} 25448c2ecf20Sopenharmony_ci 25458c2ecf20Sopenharmony_ci/* 25468c2ecf20Sopenharmony_ci * Recolve LBR callstack chain sample 25478c2ecf20Sopenharmony_ci * Return: 25488c2ecf20Sopenharmony_ci * 1 on success get LBR callchain information 25498c2ecf20Sopenharmony_ci * 0 no available LBR callchain information, should try fp 25508c2ecf20Sopenharmony_ci * negative error code on other errors. 25518c2ecf20Sopenharmony_ci */ 25528c2ecf20Sopenharmony_cistatic int resolve_lbr_callchain_sample(struct thread *thread, 25538c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 25548c2ecf20Sopenharmony_ci struct perf_sample *sample, 25558c2ecf20Sopenharmony_ci struct symbol **parent, 25568c2ecf20Sopenharmony_ci struct addr_location *root_al, 25578c2ecf20Sopenharmony_ci int max_stack, 25588c2ecf20Sopenharmony_ci unsigned int max_lbr) 25598c2ecf20Sopenharmony_ci{ 25608c2ecf20Sopenharmony_ci bool callee = (callchain_param.order == ORDER_CALLEE); 25618c2ecf20Sopenharmony_ci struct ip_callchain *chain = sample->callchain; 25628c2ecf20Sopenharmony_ci int chain_nr = min(max_stack, (int)chain->nr), i; 25638c2ecf20Sopenharmony_ci struct lbr_stitch *lbr_stitch; 25648c2ecf20Sopenharmony_ci bool stitched_lbr = false; 25658c2ecf20Sopenharmony_ci u64 branch_from = 0; 25668c2ecf20Sopenharmony_ci int err; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci for (i = 0; i < chain_nr; i++) { 25698c2ecf20Sopenharmony_ci if (chain->ips[i] == PERF_CONTEXT_USER) 25708c2ecf20Sopenharmony_ci break; 25718c2ecf20Sopenharmony_ci } 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci /* LBR only affects the user callchain */ 25748c2ecf20Sopenharmony_ci if (i == chain_nr) 25758c2ecf20Sopenharmony_ci return 0; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci if (thread->lbr_stitch_enable && !sample->no_hw_idx && 25788c2ecf20Sopenharmony_ci (max_lbr > 0) && alloc_lbr_stitch(thread, max_lbr)) { 25798c2ecf20Sopenharmony_ci lbr_stitch = thread->lbr_stitch; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci stitched_lbr = has_stitched_lbr(thread, sample, 25828c2ecf20Sopenharmony_ci &lbr_stitch->prev_sample, 25838c2ecf20Sopenharmony_ci max_lbr, callee); 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci if (!stitched_lbr && !list_empty(&lbr_stitch->lists)) { 25868c2ecf20Sopenharmony_ci list_replace_init(&lbr_stitch->lists, 25878c2ecf20Sopenharmony_ci &lbr_stitch->free_lists); 25888c2ecf20Sopenharmony_ci } 25898c2ecf20Sopenharmony_ci memcpy(&lbr_stitch->prev_sample, sample, sizeof(*sample)); 25908c2ecf20Sopenharmony_ci } 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci if (callee) { 25938c2ecf20Sopenharmony_ci /* Add kernel ip */ 25948c2ecf20Sopenharmony_ci err = lbr_callchain_add_kernel_ip(thread, cursor, sample, 25958c2ecf20Sopenharmony_ci parent, root_al, branch_from, 25968c2ecf20Sopenharmony_ci true, i); 25978c2ecf20Sopenharmony_ci if (err) 25988c2ecf20Sopenharmony_ci goto error; 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci err = lbr_callchain_add_lbr_ip(thread, cursor, sample, parent, 26018c2ecf20Sopenharmony_ci root_al, &branch_from, true); 26028c2ecf20Sopenharmony_ci if (err) 26038c2ecf20Sopenharmony_ci goto error; 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci if (stitched_lbr) { 26068c2ecf20Sopenharmony_ci err = lbr_callchain_add_stitched_lbr_ip(thread, cursor); 26078c2ecf20Sopenharmony_ci if (err) 26088c2ecf20Sopenharmony_ci goto error; 26098c2ecf20Sopenharmony_ci } 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci } else { 26128c2ecf20Sopenharmony_ci if (stitched_lbr) { 26138c2ecf20Sopenharmony_ci err = lbr_callchain_add_stitched_lbr_ip(thread, cursor); 26148c2ecf20Sopenharmony_ci if (err) 26158c2ecf20Sopenharmony_ci goto error; 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci err = lbr_callchain_add_lbr_ip(thread, cursor, sample, parent, 26188c2ecf20Sopenharmony_ci root_al, &branch_from, false); 26198c2ecf20Sopenharmony_ci if (err) 26208c2ecf20Sopenharmony_ci goto error; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci /* Add kernel ip */ 26238c2ecf20Sopenharmony_ci err = lbr_callchain_add_kernel_ip(thread, cursor, sample, 26248c2ecf20Sopenharmony_ci parent, root_al, branch_from, 26258c2ecf20Sopenharmony_ci false, i); 26268c2ecf20Sopenharmony_ci if (err) 26278c2ecf20Sopenharmony_ci goto error; 26288c2ecf20Sopenharmony_ci } 26298c2ecf20Sopenharmony_ci return 1; 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_cierror: 26328c2ecf20Sopenharmony_ci return (err < 0) ? err : 0; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_cistatic int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, 26368c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 26378c2ecf20Sopenharmony_ci struct symbol **parent, 26388c2ecf20Sopenharmony_ci struct addr_location *root_al, 26398c2ecf20Sopenharmony_ci u8 *cpumode, int ent) 26408c2ecf20Sopenharmony_ci{ 26418c2ecf20Sopenharmony_ci int err = 0; 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci while (--ent >= 0) { 26448c2ecf20Sopenharmony_ci u64 ip = chain->ips[ent]; 26458c2ecf20Sopenharmony_ci 26468c2ecf20Sopenharmony_ci if (ip >= PERF_CONTEXT_MAX) { 26478c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 26488c2ecf20Sopenharmony_ci root_al, cpumode, ip, 26498c2ecf20Sopenharmony_ci false, NULL, NULL, 0); 26508c2ecf20Sopenharmony_ci break; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci return err; 26548c2ecf20Sopenharmony_ci} 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_cistatic int thread__resolve_callchain_sample(struct thread *thread, 26578c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 26588c2ecf20Sopenharmony_ci struct evsel *evsel, 26598c2ecf20Sopenharmony_ci struct perf_sample *sample, 26608c2ecf20Sopenharmony_ci struct symbol **parent, 26618c2ecf20Sopenharmony_ci struct addr_location *root_al, 26628c2ecf20Sopenharmony_ci int max_stack) 26638c2ecf20Sopenharmony_ci{ 26648c2ecf20Sopenharmony_ci struct branch_stack *branch = sample->branch_stack; 26658c2ecf20Sopenharmony_ci struct branch_entry *entries = perf_sample__branch_entries(sample); 26668c2ecf20Sopenharmony_ci struct ip_callchain *chain = sample->callchain; 26678c2ecf20Sopenharmony_ci int chain_nr = 0; 26688c2ecf20Sopenharmony_ci u8 cpumode = PERF_RECORD_MISC_USER; 26698c2ecf20Sopenharmony_ci int i, j, err, nr_entries; 26708c2ecf20Sopenharmony_ci int skip_idx = -1; 26718c2ecf20Sopenharmony_ci int first_call = 0; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci if (chain) 26748c2ecf20Sopenharmony_ci chain_nr = chain->nr; 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci if (evsel__has_branch_callstack(evsel)) { 26778c2ecf20Sopenharmony_ci struct perf_env *env = evsel__env(evsel); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, 26808c2ecf20Sopenharmony_ci root_al, max_stack, 26818c2ecf20Sopenharmony_ci !env ? 0 : env->max_branches); 26828c2ecf20Sopenharmony_ci if (err) 26838c2ecf20Sopenharmony_ci return (err < 0) ? err : 0; 26848c2ecf20Sopenharmony_ci } 26858c2ecf20Sopenharmony_ci 26868c2ecf20Sopenharmony_ci /* 26878c2ecf20Sopenharmony_ci * Based on DWARF debug information, some architectures skip 26888c2ecf20Sopenharmony_ci * a callchain entry saved by the kernel. 26898c2ecf20Sopenharmony_ci */ 26908c2ecf20Sopenharmony_ci skip_idx = arch_skip_callchain_idx(thread, chain); 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci /* 26938c2ecf20Sopenharmony_ci * Add branches to call stack for easier browsing. This gives 26948c2ecf20Sopenharmony_ci * more context for a sample than just the callers. 26958c2ecf20Sopenharmony_ci * 26968c2ecf20Sopenharmony_ci * This uses individual histograms of paths compared to the 26978c2ecf20Sopenharmony_ci * aggregated histograms the normal LBR mode uses. 26988c2ecf20Sopenharmony_ci * 26998c2ecf20Sopenharmony_ci * Limitations for now: 27008c2ecf20Sopenharmony_ci * - No extra filters 27018c2ecf20Sopenharmony_ci * - No annotations (should annotate somehow) 27028c2ecf20Sopenharmony_ci */ 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci if (branch && callchain_param.branch_callstack) { 27058c2ecf20Sopenharmony_ci int nr = min(max_stack, (int)branch->nr); 27068c2ecf20Sopenharmony_ci struct branch_entry be[nr]; 27078c2ecf20Sopenharmony_ci struct iterations iter[nr]; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ci if (branch->nr > PERF_MAX_BRANCH_DEPTH) { 27108c2ecf20Sopenharmony_ci pr_warning("corrupted branch chain. skipping...\n"); 27118c2ecf20Sopenharmony_ci goto check_calls; 27128c2ecf20Sopenharmony_ci } 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 27158c2ecf20Sopenharmony_ci if (callchain_param.order == ORDER_CALLEE) { 27168c2ecf20Sopenharmony_ci be[i] = entries[i]; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci if (chain == NULL) 27198c2ecf20Sopenharmony_ci continue; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci /* 27228c2ecf20Sopenharmony_ci * Check for overlap into the callchain. 27238c2ecf20Sopenharmony_ci * The return address is one off compared to 27248c2ecf20Sopenharmony_ci * the branch entry. To adjust for this 27258c2ecf20Sopenharmony_ci * assume the calling instruction is not longer 27268c2ecf20Sopenharmony_ci * than 8 bytes. 27278c2ecf20Sopenharmony_ci */ 27288c2ecf20Sopenharmony_ci if (i == skip_idx || 27298c2ecf20Sopenharmony_ci chain->ips[first_call] >= PERF_CONTEXT_MAX) 27308c2ecf20Sopenharmony_ci first_call++; 27318c2ecf20Sopenharmony_ci else if (be[i].from < chain->ips[first_call] && 27328c2ecf20Sopenharmony_ci be[i].from >= chain->ips[first_call] - 8) 27338c2ecf20Sopenharmony_ci first_call++; 27348c2ecf20Sopenharmony_ci } else 27358c2ecf20Sopenharmony_ci be[i] = entries[branch->nr - i - 1]; 27368c2ecf20Sopenharmony_ci } 27378c2ecf20Sopenharmony_ci 27388c2ecf20Sopenharmony_ci memset(iter, 0, sizeof(struct iterations) * nr); 27398c2ecf20Sopenharmony_ci nr = remove_loops(be, nr, iter); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 27428c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 27438c2ecf20Sopenharmony_ci root_al, 27448c2ecf20Sopenharmony_ci NULL, be[i].to, 27458c2ecf20Sopenharmony_ci true, &be[i].flags, 27468c2ecf20Sopenharmony_ci NULL, be[i].from); 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_ci if (!err) 27498c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, root_al, 27508c2ecf20Sopenharmony_ci NULL, be[i].from, 27518c2ecf20Sopenharmony_ci true, &be[i].flags, 27528c2ecf20Sopenharmony_ci &iter[i], 0); 27538c2ecf20Sopenharmony_ci if (err == -EINVAL) 27548c2ecf20Sopenharmony_ci break; 27558c2ecf20Sopenharmony_ci if (err) 27568c2ecf20Sopenharmony_ci return err; 27578c2ecf20Sopenharmony_ci } 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci if (chain_nr == 0) 27608c2ecf20Sopenharmony_ci return 0; 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci chain_nr -= nr; 27638c2ecf20Sopenharmony_ci } 27648c2ecf20Sopenharmony_ci 27658c2ecf20Sopenharmony_cicheck_calls: 27668c2ecf20Sopenharmony_ci if (chain && callchain_param.order != ORDER_CALLEE) { 27678c2ecf20Sopenharmony_ci err = find_prev_cpumode(chain, thread, cursor, parent, root_al, 27688c2ecf20Sopenharmony_ci &cpumode, chain->nr - first_call); 27698c2ecf20Sopenharmony_ci if (err) 27708c2ecf20Sopenharmony_ci return (err < 0) ? err : 0; 27718c2ecf20Sopenharmony_ci } 27728c2ecf20Sopenharmony_ci for (i = first_call, nr_entries = 0; 27738c2ecf20Sopenharmony_ci i < chain_nr && nr_entries < max_stack; i++) { 27748c2ecf20Sopenharmony_ci u64 ip; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci if (callchain_param.order == ORDER_CALLEE) 27778c2ecf20Sopenharmony_ci j = i; 27788c2ecf20Sopenharmony_ci else 27798c2ecf20Sopenharmony_ci j = chain->nr - i - 1; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci#ifdef HAVE_SKIP_CALLCHAIN_IDX 27828c2ecf20Sopenharmony_ci if (j == skip_idx) 27838c2ecf20Sopenharmony_ci continue; 27848c2ecf20Sopenharmony_ci#endif 27858c2ecf20Sopenharmony_ci ip = chain->ips[j]; 27868c2ecf20Sopenharmony_ci if (ip < PERF_CONTEXT_MAX) 27878c2ecf20Sopenharmony_ci ++nr_entries; 27888c2ecf20Sopenharmony_ci else if (callchain_param.order != ORDER_CALLEE) { 27898c2ecf20Sopenharmony_ci err = find_prev_cpumode(chain, thread, cursor, parent, 27908c2ecf20Sopenharmony_ci root_al, &cpumode, j); 27918c2ecf20Sopenharmony_ci if (err) 27928c2ecf20Sopenharmony_ci return (err < 0) ? err : 0; 27938c2ecf20Sopenharmony_ci continue; 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 27978c2ecf20Sopenharmony_ci root_al, &cpumode, ip, 27988c2ecf20Sopenharmony_ci false, NULL, NULL, 0); 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci if (err) 28018c2ecf20Sopenharmony_ci return (err < 0) ? err : 0; 28028c2ecf20Sopenharmony_ci } 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci return 0; 28058c2ecf20Sopenharmony_ci} 28068c2ecf20Sopenharmony_ci 28078c2ecf20Sopenharmony_cistatic int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip) 28088c2ecf20Sopenharmony_ci{ 28098c2ecf20Sopenharmony_ci struct symbol *sym = ms->sym; 28108c2ecf20Sopenharmony_ci struct map *map = ms->map; 28118c2ecf20Sopenharmony_ci struct inline_node *inline_node; 28128c2ecf20Sopenharmony_ci struct inline_list *ilist; 28138c2ecf20Sopenharmony_ci u64 addr; 28148c2ecf20Sopenharmony_ci int ret = 1; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci if (!symbol_conf.inline_name || !map || !sym) 28178c2ecf20Sopenharmony_ci return ret; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci addr = map__map_ip(map, ip); 28208c2ecf20Sopenharmony_ci addr = map__rip_2objdump(map, addr); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci inline_node = inlines__tree_find(&map->dso->inlined_nodes, addr); 28238c2ecf20Sopenharmony_ci if (!inline_node) { 28248c2ecf20Sopenharmony_ci inline_node = dso__parse_addr_inlines(map->dso, addr, sym); 28258c2ecf20Sopenharmony_ci if (!inline_node) 28268c2ecf20Sopenharmony_ci return ret; 28278c2ecf20Sopenharmony_ci inlines__tree_insert(&map->dso->inlined_nodes, inline_node); 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci list_for_each_entry(ilist, &inline_node->val, list) { 28318c2ecf20Sopenharmony_ci struct map_symbol ilist_ms = { 28328c2ecf20Sopenharmony_ci .maps = ms->maps, 28338c2ecf20Sopenharmony_ci .map = map, 28348c2ecf20Sopenharmony_ci .sym = ilist->symbol, 28358c2ecf20Sopenharmony_ci }; 28368c2ecf20Sopenharmony_ci ret = callchain_cursor_append(cursor, ip, &ilist_ms, false, 28378c2ecf20Sopenharmony_ci NULL, 0, 0, 0, ilist->srcline); 28388c2ecf20Sopenharmony_ci 28398c2ecf20Sopenharmony_ci if (ret != 0) 28408c2ecf20Sopenharmony_ci return ret; 28418c2ecf20Sopenharmony_ci } 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci return ret; 28448c2ecf20Sopenharmony_ci} 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_cistatic int unwind_entry(struct unwind_entry *entry, void *arg) 28478c2ecf20Sopenharmony_ci{ 28488c2ecf20Sopenharmony_ci struct callchain_cursor *cursor = arg; 28498c2ecf20Sopenharmony_ci const char *srcline = NULL; 28508c2ecf20Sopenharmony_ci u64 addr = entry->ip; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci if (symbol_conf.hide_unresolved && entry->ms.sym == NULL) 28538c2ecf20Sopenharmony_ci return 0; 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci if (append_inlines(cursor, &entry->ms, entry->ip) == 0) 28568c2ecf20Sopenharmony_ci return 0; 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci /* 28598c2ecf20Sopenharmony_ci * Convert entry->ip from a virtual address to an offset in 28608c2ecf20Sopenharmony_ci * its corresponding binary. 28618c2ecf20Sopenharmony_ci */ 28628c2ecf20Sopenharmony_ci if (entry->ms.map) 28638c2ecf20Sopenharmony_ci addr = map__map_ip(entry->ms.map, entry->ip); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci srcline = callchain_srcline(&entry->ms, addr); 28668c2ecf20Sopenharmony_ci return callchain_cursor_append(cursor, entry->ip, &entry->ms, 28678c2ecf20Sopenharmony_ci false, NULL, 0, 0, 0, srcline); 28688c2ecf20Sopenharmony_ci} 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_cistatic int thread__resolve_callchain_unwind(struct thread *thread, 28718c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 28728c2ecf20Sopenharmony_ci struct evsel *evsel, 28738c2ecf20Sopenharmony_ci struct perf_sample *sample, 28748c2ecf20Sopenharmony_ci int max_stack) 28758c2ecf20Sopenharmony_ci{ 28768c2ecf20Sopenharmony_ci /* Can we do dwarf post unwind? */ 28778c2ecf20Sopenharmony_ci if (!((evsel->core.attr.sample_type & PERF_SAMPLE_REGS_USER) && 28788c2ecf20Sopenharmony_ci (evsel->core.attr.sample_type & PERF_SAMPLE_STACK_USER))) 28798c2ecf20Sopenharmony_ci return 0; 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci /* Bail out if nothing was captured. */ 28828c2ecf20Sopenharmony_ci if ((!sample->user_regs.regs) || 28838c2ecf20Sopenharmony_ci (!sample->user_stack.size)) 28848c2ecf20Sopenharmony_ci return 0; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci return unwind__get_entries(unwind_entry, cursor, 28878c2ecf20Sopenharmony_ci thread, sample, max_stack); 28888c2ecf20Sopenharmony_ci} 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ciint thread__resolve_callchain(struct thread *thread, 28918c2ecf20Sopenharmony_ci struct callchain_cursor *cursor, 28928c2ecf20Sopenharmony_ci struct evsel *evsel, 28938c2ecf20Sopenharmony_ci struct perf_sample *sample, 28948c2ecf20Sopenharmony_ci struct symbol **parent, 28958c2ecf20Sopenharmony_ci struct addr_location *root_al, 28968c2ecf20Sopenharmony_ci int max_stack) 28978c2ecf20Sopenharmony_ci{ 28988c2ecf20Sopenharmony_ci int ret = 0; 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci callchain_cursor_reset(cursor); 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci if (callchain_param.order == ORDER_CALLEE) { 29038c2ecf20Sopenharmony_ci ret = thread__resolve_callchain_sample(thread, cursor, 29048c2ecf20Sopenharmony_ci evsel, sample, 29058c2ecf20Sopenharmony_ci parent, root_al, 29068c2ecf20Sopenharmony_ci max_stack); 29078c2ecf20Sopenharmony_ci if (ret) 29088c2ecf20Sopenharmony_ci return ret; 29098c2ecf20Sopenharmony_ci ret = thread__resolve_callchain_unwind(thread, cursor, 29108c2ecf20Sopenharmony_ci evsel, sample, 29118c2ecf20Sopenharmony_ci max_stack); 29128c2ecf20Sopenharmony_ci } else { 29138c2ecf20Sopenharmony_ci ret = thread__resolve_callchain_unwind(thread, cursor, 29148c2ecf20Sopenharmony_ci evsel, sample, 29158c2ecf20Sopenharmony_ci max_stack); 29168c2ecf20Sopenharmony_ci if (ret) 29178c2ecf20Sopenharmony_ci return ret; 29188c2ecf20Sopenharmony_ci ret = thread__resolve_callchain_sample(thread, cursor, 29198c2ecf20Sopenharmony_ci evsel, sample, 29208c2ecf20Sopenharmony_ci parent, root_al, 29218c2ecf20Sopenharmony_ci max_stack); 29228c2ecf20Sopenharmony_ci } 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci return ret; 29258c2ecf20Sopenharmony_ci} 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ciint machine__for_each_thread(struct machine *machine, 29288c2ecf20Sopenharmony_ci int (*fn)(struct thread *thread, void *p), 29298c2ecf20Sopenharmony_ci void *priv) 29308c2ecf20Sopenharmony_ci{ 29318c2ecf20Sopenharmony_ci struct threads *threads; 29328c2ecf20Sopenharmony_ci struct rb_node *nd; 29338c2ecf20Sopenharmony_ci struct thread *thread; 29348c2ecf20Sopenharmony_ci int rc = 0; 29358c2ecf20Sopenharmony_ci int i; 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 29388c2ecf20Sopenharmony_ci threads = &machine->threads[i]; 29398c2ecf20Sopenharmony_ci for (nd = rb_first_cached(&threads->entries); nd; 29408c2ecf20Sopenharmony_ci nd = rb_next(nd)) { 29418c2ecf20Sopenharmony_ci thread = rb_entry(nd, struct thread, rb_node); 29428c2ecf20Sopenharmony_ci rc = fn(thread, priv); 29438c2ecf20Sopenharmony_ci if (rc != 0) 29448c2ecf20Sopenharmony_ci return rc; 29458c2ecf20Sopenharmony_ci } 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_ci list_for_each_entry(thread, &threads->dead, node) { 29488c2ecf20Sopenharmony_ci rc = fn(thread, priv); 29498c2ecf20Sopenharmony_ci if (rc != 0) 29508c2ecf20Sopenharmony_ci return rc; 29518c2ecf20Sopenharmony_ci } 29528c2ecf20Sopenharmony_ci } 29538c2ecf20Sopenharmony_ci return rc; 29548c2ecf20Sopenharmony_ci} 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ciint machines__for_each_thread(struct machines *machines, 29578c2ecf20Sopenharmony_ci int (*fn)(struct thread *thread, void *p), 29588c2ecf20Sopenharmony_ci void *priv) 29598c2ecf20Sopenharmony_ci{ 29608c2ecf20Sopenharmony_ci struct rb_node *nd; 29618c2ecf20Sopenharmony_ci int rc = 0; 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci rc = machine__for_each_thread(&machines->host, fn, priv); 29648c2ecf20Sopenharmony_ci if (rc != 0) 29658c2ecf20Sopenharmony_ci return rc; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 29688c2ecf20Sopenharmony_ci struct machine *machine = rb_entry(nd, struct machine, rb_node); 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci rc = machine__for_each_thread(machine, fn, priv); 29718c2ecf20Sopenharmony_ci if (rc != 0) 29728c2ecf20Sopenharmony_ci return rc; 29738c2ecf20Sopenharmony_ci } 29748c2ecf20Sopenharmony_ci return rc; 29758c2ecf20Sopenharmony_ci} 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_cipid_t machine__get_current_tid(struct machine *machine, int cpu) 29788c2ecf20Sopenharmony_ci{ 29798c2ecf20Sopenharmony_ci int nr_cpus = min(machine->env->nr_cpus_avail, MAX_NR_CPUS); 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci if (cpu < 0 || cpu >= nr_cpus || !machine->current_tid) 29828c2ecf20Sopenharmony_ci return -1; 29838c2ecf20Sopenharmony_ci 29848c2ecf20Sopenharmony_ci return machine->current_tid[cpu]; 29858c2ecf20Sopenharmony_ci} 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ciint machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, 29888c2ecf20Sopenharmony_ci pid_t tid) 29898c2ecf20Sopenharmony_ci{ 29908c2ecf20Sopenharmony_ci struct thread *thread; 29918c2ecf20Sopenharmony_ci int nr_cpus = min(machine->env->nr_cpus_avail, MAX_NR_CPUS); 29928c2ecf20Sopenharmony_ci 29938c2ecf20Sopenharmony_ci if (cpu < 0) 29948c2ecf20Sopenharmony_ci return -EINVAL; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci if (!machine->current_tid) { 29978c2ecf20Sopenharmony_ci int i; 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci machine->current_tid = calloc(nr_cpus, sizeof(pid_t)); 30008c2ecf20Sopenharmony_ci if (!machine->current_tid) 30018c2ecf20Sopenharmony_ci return -ENOMEM; 30028c2ecf20Sopenharmony_ci for (i = 0; i < nr_cpus; i++) 30038c2ecf20Sopenharmony_ci machine->current_tid[i] = -1; 30048c2ecf20Sopenharmony_ci } 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci if (cpu >= nr_cpus) { 30078c2ecf20Sopenharmony_ci pr_err("Requested CPU %d too large. ", cpu); 30088c2ecf20Sopenharmony_ci pr_err("Consider raising MAX_NR_CPUS\n"); 30098c2ecf20Sopenharmony_ci return -EINVAL; 30108c2ecf20Sopenharmony_ci } 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci machine->current_tid[cpu] = tid; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, pid, tid); 30158c2ecf20Sopenharmony_ci if (!thread) 30168c2ecf20Sopenharmony_ci return -ENOMEM; 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci thread->cpu = cpu; 30198c2ecf20Sopenharmony_ci thread__put(thread); 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci return 0; 30228c2ecf20Sopenharmony_ci} 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci/* 30258c2ecf20Sopenharmony_ci * Compares the raw arch string. N.B. see instead perf_env__arch() if a 30268c2ecf20Sopenharmony_ci * normalized arch is needed. 30278c2ecf20Sopenharmony_ci */ 30288c2ecf20Sopenharmony_cibool machine__is(struct machine *machine, const char *arch) 30298c2ecf20Sopenharmony_ci{ 30308c2ecf20Sopenharmony_ci return machine && !strcmp(perf_env__raw_arch(machine->env), arch); 30318c2ecf20Sopenharmony_ci} 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ciint machine__nr_cpus_avail(struct machine *machine) 30348c2ecf20Sopenharmony_ci{ 30358c2ecf20Sopenharmony_ci return machine ? perf_env__nr_cpus_avail(machine->env) : 0; 30368c2ecf20Sopenharmony_ci} 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ciint machine__get_kernel_start(struct machine *machine) 30398c2ecf20Sopenharmony_ci{ 30408c2ecf20Sopenharmony_ci struct map *map = machine__kernel_map(machine); 30418c2ecf20Sopenharmony_ci int err = 0; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_ci /* 30448c2ecf20Sopenharmony_ci * The only addresses above 2^63 are kernel addresses of a 64-bit 30458c2ecf20Sopenharmony_ci * kernel. Note that addresses are unsigned so that on a 32-bit system 30468c2ecf20Sopenharmony_ci * all addresses including kernel addresses are less than 2^32. In 30478c2ecf20Sopenharmony_ci * that case (32-bit system), if the kernel mapping is unknown, all 30488c2ecf20Sopenharmony_ci * addresses will be assumed to be in user space - see 30498c2ecf20Sopenharmony_ci * machine__kernel_ip(). 30508c2ecf20Sopenharmony_ci */ 30518c2ecf20Sopenharmony_ci machine->kernel_start = 1ULL << 63; 30528c2ecf20Sopenharmony_ci if (map) { 30538c2ecf20Sopenharmony_ci err = map__load(map); 30548c2ecf20Sopenharmony_ci /* 30558c2ecf20Sopenharmony_ci * On x86_64, PTI entry trampolines are less than the 30568c2ecf20Sopenharmony_ci * start of kernel text, but still above 2^63. So leave 30578c2ecf20Sopenharmony_ci * kernel_start = 1ULL << 63 for x86_64. 30588c2ecf20Sopenharmony_ci */ 30598c2ecf20Sopenharmony_ci if (!err && !machine__is(machine, "x86_64")) 30608c2ecf20Sopenharmony_ci machine->kernel_start = map->start; 30618c2ecf20Sopenharmony_ci } 30628c2ecf20Sopenharmony_ci return err; 30638c2ecf20Sopenharmony_ci} 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ciu8 machine__addr_cpumode(struct machine *machine, u8 cpumode, u64 addr) 30668c2ecf20Sopenharmony_ci{ 30678c2ecf20Sopenharmony_ci u8 addr_cpumode = cpumode; 30688c2ecf20Sopenharmony_ci bool kernel_ip; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci if (!machine->single_address_space) 30718c2ecf20Sopenharmony_ci goto out; 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci kernel_ip = machine__kernel_ip(machine, addr); 30748c2ecf20Sopenharmony_ci switch (cpumode) { 30758c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_KERNEL: 30768c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_USER: 30778c2ecf20Sopenharmony_ci addr_cpumode = kernel_ip ? PERF_RECORD_MISC_KERNEL : 30788c2ecf20Sopenharmony_ci PERF_RECORD_MISC_USER; 30798c2ecf20Sopenharmony_ci break; 30808c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_GUEST_KERNEL: 30818c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_GUEST_USER: 30828c2ecf20Sopenharmony_ci addr_cpumode = kernel_ip ? PERF_RECORD_MISC_GUEST_KERNEL : 30838c2ecf20Sopenharmony_ci PERF_RECORD_MISC_GUEST_USER; 30848c2ecf20Sopenharmony_ci break; 30858c2ecf20Sopenharmony_ci default: 30868c2ecf20Sopenharmony_ci break; 30878c2ecf20Sopenharmony_ci } 30888c2ecf20Sopenharmony_ciout: 30898c2ecf20Sopenharmony_ci return addr_cpumode; 30908c2ecf20Sopenharmony_ci} 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_cistruct dso *machine__findnew_dso_id(struct machine *machine, const char *filename, struct dso_id *id) 30938c2ecf20Sopenharmony_ci{ 30948c2ecf20Sopenharmony_ci return dsos__findnew_id(&machine->dsos, filename, id); 30958c2ecf20Sopenharmony_ci} 30968c2ecf20Sopenharmony_ci 30978c2ecf20Sopenharmony_cistruct dso *machine__findnew_dso(struct machine *machine, const char *filename) 30988c2ecf20Sopenharmony_ci{ 30998c2ecf20Sopenharmony_ci return machine__findnew_dso_id(machine, filename, NULL); 31008c2ecf20Sopenharmony_ci} 31018c2ecf20Sopenharmony_ci 31028c2ecf20Sopenharmony_cichar *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp) 31038c2ecf20Sopenharmony_ci{ 31048c2ecf20Sopenharmony_ci struct machine *machine = vmachine; 31058c2ecf20Sopenharmony_ci struct map *map; 31068c2ecf20Sopenharmony_ci struct symbol *sym = machine__find_kernel_symbol(machine, *addrp, &map); 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci if (sym == NULL) 31098c2ecf20Sopenharmony_ci return NULL; 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci *modp = __map__is_kmodule(map) ? (char *)map->dso->short_name : NULL; 31128c2ecf20Sopenharmony_ci *addrp = map->unmap_ip(map, sym->start); 31138c2ecf20Sopenharmony_ci return sym->name; 31148c2ecf20Sopenharmony_ci} 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ciint machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv) 31178c2ecf20Sopenharmony_ci{ 31188c2ecf20Sopenharmony_ci struct dso *pos; 31198c2ecf20Sopenharmony_ci int err = 0; 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci list_for_each_entry(pos, &machine->dsos.head, node) { 31228c2ecf20Sopenharmony_ci if (fn(pos, machine, priv)) 31238c2ecf20Sopenharmony_ci err = -1; 31248c2ecf20Sopenharmony_ci } 31258c2ecf20Sopenharmony_ci return err; 31268c2ecf20Sopenharmony_ci} 3127