162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <dirent.h> 362306a36Sopenharmony_ci#include <errno.h> 462306a36Sopenharmony_ci#include <inttypes.h> 562306a36Sopenharmony_ci#include <regex.h> 662306a36Sopenharmony_ci#include <stdlib.h> 762306a36Sopenharmony_ci#include "callchain.h" 862306a36Sopenharmony_ci#include "debug.h" 962306a36Sopenharmony_ci#include "dso.h" 1062306a36Sopenharmony_ci#include "env.h" 1162306a36Sopenharmony_ci#include "event.h" 1262306a36Sopenharmony_ci#include "evsel.h" 1362306a36Sopenharmony_ci#include "hist.h" 1462306a36Sopenharmony_ci#include "machine.h" 1562306a36Sopenharmony_ci#include "map.h" 1662306a36Sopenharmony_ci#include "map_symbol.h" 1762306a36Sopenharmony_ci#include "branch.h" 1862306a36Sopenharmony_ci#include "mem-events.h" 1962306a36Sopenharmony_ci#include "path.h" 2062306a36Sopenharmony_ci#include "srcline.h" 2162306a36Sopenharmony_ci#include "symbol.h" 2262306a36Sopenharmony_ci#include "sort.h" 2362306a36Sopenharmony_ci#include "strlist.h" 2462306a36Sopenharmony_ci#include "target.h" 2562306a36Sopenharmony_ci#include "thread.h" 2662306a36Sopenharmony_ci#include "util.h" 2762306a36Sopenharmony_ci#include "vdso.h" 2862306a36Sopenharmony_ci#include <stdbool.h> 2962306a36Sopenharmony_ci#include <sys/types.h> 3062306a36Sopenharmony_ci#include <sys/stat.h> 3162306a36Sopenharmony_ci#include <unistd.h> 3262306a36Sopenharmony_ci#include "unwind.h" 3362306a36Sopenharmony_ci#include "linux/hash.h" 3462306a36Sopenharmony_ci#include "asm/bug.h" 3562306a36Sopenharmony_ci#include "bpf-event.h" 3662306a36Sopenharmony_ci#include <internal/lib.h> // page_size 3762306a36Sopenharmony_ci#include "cgroup.h" 3862306a36Sopenharmony_ci#include "arm64-frame-pointer-unwind-support.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include <linux/ctype.h> 4162306a36Sopenharmony_ci#include <symbol/kallsyms.h> 4262306a36Sopenharmony_ci#include <linux/mman.h> 4362306a36Sopenharmony_ci#include <linux/string.h> 4462306a36Sopenharmony_ci#include <linux/zalloc.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void __machine__remove_thread(struct machine *machine, struct thread_rb_node *nd, 4762306a36Sopenharmony_ci struct thread *th, bool lock); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic struct dso *machine__kernel_dso(struct machine *machine) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci return map__dso(machine->vmlinux_map); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void dsos__init(struct dsos *dsos) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci INIT_LIST_HEAD(&dsos->head); 5762306a36Sopenharmony_ci dsos->root = RB_ROOT; 5862306a36Sopenharmony_ci init_rwsem(&dsos->lock); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void machine__threads_init(struct machine *machine) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci int i; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 6662306a36Sopenharmony_ci struct threads *threads = &machine->threads[i]; 6762306a36Sopenharmony_ci threads->entries = RB_ROOT_CACHED; 6862306a36Sopenharmony_ci init_rwsem(&threads->lock); 6962306a36Sopenharmony_ci threads->nr = 0; 7062306a36Sopenharmony_ci INIT_LIST_HEAD(&threads->dead); 7162306a36Sopenharmony_ci threads->last_match = NULL; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int thread_rb_node__cmp_tid(const void *key, const struct rb_node *nd) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci int to_find = (int) *((pid_t *)key); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci return to_find - (int)thread__tid(rb_entry(nd, struct thread_rb_node, rb_node)->thread); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic struct thread_rb_node *thread_rb_node__find(const struct thread *th, 8362306a36Sopenharmony_ci struct rb_root *tree) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci pid_t to_find = thread__tid(th); 8662306a36Sopenharmony_ci struct rb_node *nd = rb_find(&to_find, tree, thread_rb_node__cmp_tid); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci return rb_entry(nd, struct thread_rb_node, rb_node); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int machine__set_mmap_name(struct machine *machine) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci if (machine__is_host(machine)) 9462306a36Sopenharmony_ci machine->mmap_name = strdup("[kernel.kallsyms]"); 9562306a36Sopenharmony_ci else if (machine__is_default_guest(machine)) 9662306a36Sopenharmony_ci machine->mmap_name = strdup("[guest.kernel.kallsyms]"); 9762306a36Sopenharmony_ci else if (asprintf(&machine->mmap_name, "[guest.kernel.kallsyms.%d]", 9862306a36Sopenharmony_ci machine->pid) < 0) 9962306a36Sopenharmony_ci machine->mmap_name = NULL; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return machine->mmap_name ? 0 : -ENOMEM; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void thread__set_guest_comm(struct thread *thread, pid_t pid) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci char comm[64]; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci snprintf(comm, sizeof(comm), "[guest/%d]", pid); 10962306a36Sopenharmony_ci thread__set_comm(thread, comm, 0); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciint machine__init(struct machine *machine, const char *root_dir, pid_t pid) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci int err = -ENOMEM; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci memset(machine, 0, sizeof(*machine)); 11762306a36Sopenharmony_ci machine->kmaps = maps__new(machine); 11862306a36Sopenharmony_ci if (machine->kmaps == NULL) 11962306a36Sopenharmony_ci return -ENOMEM; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci RB_CLEAR_NODE(&machine->rb_node); 12262306a36Sopenharmony_ci dsos__init(&machine->dsos); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci machine__threads_init(machine); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci machine->vdso_info = NULL; 12762306a36Sopenharmony_ci machine->env = NULL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci machine->pid = pid; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci machine->id_hdr_size = 0; 13262306a36Sopenharmony_ci machine->kptr_restrict_warned = false; 13362306a36Sopenharmony_ci machine->comm_exec = false; 13462306a36Sopenharmony_ci machine->kernel_start = 0; 13562306a36Sopenharmony_ci machine->vmlinux_map = NULL; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci machine->root_dir = strdup(root_dir); 13862306a36Sopenharmony_ci if (machine->root_dir == NULL) 13962306a36Sopenharmony_ci goto out; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (machine__set_mmap_name(machine)) 14262306a36Sopenharmony_ci goto out; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (pid != HOST_KERNEL_ID) { 14562306a36Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, -1, 14662306a36Sopenharmony_ci pid); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (thread == NULL) 14962306a36Sopenharmony_ci goto out; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci thread__set_guest_comm(thread, pid); 15262306a36Sopenharmony_ci thread__put(thread); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci machine->current_tid = NULL; 15662306a36Sopenharmony_ci err = 0; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ciout: 15962306a36Sopenharmony_ci if (err) { 16062306a36Sopenharmony_ci zfree(&machine->kmaps); 16162306a36Sopenharmony_ci zfree(&machine->root_dir); 16262306a36Sopenharmony_ci zfree(&machine->mmap_name); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci return 0; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistruct machine *machine__new_host(void) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct machine *machine = malloc(sizeof(*machine)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (machine != NULL) { 17262306a36Sopenharmony_ci machine__init(machine, "", HOST_KERNEL_ID); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (machine__create_kernel_maps(machine) < 0) 17562306a36Sopenharmony_ci goto out_delete; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci return machine; 17962306a36Sopenharmony_ciout_delete: 18062306a36Sopenharmony_ci free(machine); 18162306a36Sopenharmony_ci return NULL; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistruct machine *machine__new_kallsyms(void) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct machine *machine = machine__new_host(); 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * FIXME: 18962306a36Sopenharmony_ci * 1) We should switch to machine__load_kallsyms(), i.e. not explicitly 19062306a36Sopenharmony_ci * ask for not using the kcore parsing code, once this one is fixed 19162306a36Sopenharmony_ci * to create a map per module. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ci if (machine && machine__load_kallsyms(machine, "/proc/kallsyms") <= 0) { 19462306a36Sopenharmony_ci machine__delete(machine); 19562306a36Sopenharmony_ci machine = NULL; 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return machine; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic void dsos__purge(struct dsos *dsos) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct dso *pos, *n; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci down_write(&dsos->lock); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci list_for_each_entry_safe(pos, n, &dsos->head, node) { 20862306a36Sopenharmony_ci RB_CLEAR_NODE(&pos->rb_node); 20962306a36Sopenharmony_ci pos->root = NULL; 21062306a36Sopenharmony_ci list_del_init(&pos->node); 21162306a36Sopenharmony_ci dso__put(pos); 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci up_write(&dsos->lock); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void dsos__exit(struct dsos *dsos) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci dsos__purge(dsos); 22062306a36Sopenharmony_ci exit_rwsem(&dsos->lock); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_civoid machine__delete_threads(struct machine *machine) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct rb_node *nd; 22662306a36Sopenharmony_ci int i; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 22962306a36Sopenharmony_ci struct threads *threads = &machine->threads[i]; 23062306a36Sopenharmony_ci down_write(&threads->lock); 23162306a36Sopenharmony_ci nd = rb_first_cached(&threads->entries); 23262306a36Sopenharmony_ci while (nd) { 23362306a36Sopenharmony_ci struct thread_rb_node *trb = rb_entry(nd, struct thread_rb_node, rb_node); 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci nd = rb_next(nd); 23662306a36Sopenharmony_ci __machine__remove_thread(machine, trb, trb->thread, false); 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci up_write(&threads->lock); 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_civoid machine__exit(struct machine *machine) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci int i; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci if (machine == NULL) 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci machine__destroy_kernel_maps(machine); 25062306a36Sopenharmony_ci maps__zput(machine->kmaps); 25162306a36Sopenharmony_ci dsos__exit(&machine->dsos); 25262306a36Sopenharmony_ci machine__exit_vdso(machine); 25362306a36Sopenharmony_ci zfree(&machine->root_dir); 25462306a36Sopenharmony_ci zfree(&machine->mmap_name); 25562306a36Sopenharmony_ci zfree(&machine->current_tid); 25662306a36Sopenharmony_ci zfree(&machine->kallsyms_filename); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci machine__delete_threads(machine); 25962306a36Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 26062306a36Sopenharmony_ci struct threads *threads = &machine->threads[i]; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci exit_rwsem(&threads->lock); 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_civoid machine__delete(struct machine *machine) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci if (machine) { 26962306a36Sopenharmony_ci machine__exit(machine); 27062306a36Sopenharmony_ci free(machine); 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_civoid machines__init(struct machines *machines) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci machine__init(&machines->host, "", HOST_KERNEL_ID); 27762306a36Sopenharmony_ci machines->guests = RB_ROOT_CACHED; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_civoid machines__exit(struct machines *machines) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci machine__exit(&machines->host); 28362306a36Sopenharmony_ci /* XXX exit guest */ 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistruct machine *machines__add(struct machines *machines, pid_t pid, 28762306a36Sopenharmony_ci const char *root_dir) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct rb_node **p = &machines->guests.rb_root.rb_node; 29062306a36Sopenharmony_ci struct rb_node *parent = NULL; 29162306a36Sopenharmony_ci struct machine *pos, *machine = malloc(sizeof(*machine)); 29262306a36Sopenharmony_ci bool leftmost = true; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (machine == NULL) 29562306a36Sopenharmony_ci return NULL; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (machine__init(machine, root_dir, pid) != 0) { 29862306a36Sopenharmony_ci free(machine); 29962306a36Sopenharmony_ci return NULL; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci while (*p != NULL) { 30362306a36Sopenharmony_ci parent = *p; 30462306a36Sopenharmony_ci pos = rb_entry(parent, struct machine, rb_node); 30562306a36Sopenharmony_ci if (pid < pos->pid) 30662306a36Sopenharmony_ci p = &(*p)->rb_left; 30762306a36Sopenharmony_ci else { 30862306a36Sopenharmony_ci p = &(*p)->rb_right; 30962306a36Sopenharmony_ci leftmost = false; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci rb_link_node(&machine->rb_node, parent, p); 31462306a36Sopenharmony_ci rb_insert_color_cached(&machine->rb_node, &machines->guests, leftmost); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci machine->machines = machines; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return machine; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_civoid machines__set_comm_exec(struct machines *machines, bool comm_exec) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct rb_node *nd; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci machines->host.comm_exec = comm_exec; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 32862306a36Sopenharmony_ci struct machine *machine = rb_entry(nd, struct machine, rb_node); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci machine->comm_exec = comm_exec; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistruct machine *machines__find(struct machines *machines, pid_t pid) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct rb_node **p = &machines->guests.rb_root.rb_node; 33762306a36Sopenharmony_ci struct rb_node *parent = NULL; 33862306a36Sopenharmony_ci struct machine *machine; 33962306a36Sopenharmony_ci struct machine *default_machine = NULL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (pid == HOST_KERNEL_ID) 34262306a36Sopenharmony_ci return &machines->host; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci while (*p != NULL) { 34562306a36Sopenharmony_ci parent = *p; 34662306a36Sopenharmony_ci machine = rb_entry(parent, struct machine, rb_node); 34762306a36Sopenharmony_ci if (pid < machine->pid) 34862306a36Sopenharmony_ci p = &(*p)->rb_left; 34962306a36Sopenharmony_ci else if (pid > machine->pid) 35062306a36Sopenharmony_ci p = &(*p)->rb_right; 35162306a36Sopenharmony_ci else 35262306a36Sopenharmony_ci return machine; 35362306a36Sopenharmony_ci if (!machine->pid) 35462306a36Sopenharmony_ci default_machine = machine; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return default_machine; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistruct machine *machines__findnew(struct machines *machines, pid_t pid) 36162306a36Sopenharmony_ci{ 36262306a36Sopenharmony_ci char path[PATH_MAX]; 36362306a36Sopenharmony_ci const char *root_dir = ""; 36462306a36Sopenharmony_ci struct machine *machine = machines__find(machines, pid); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (machine && (machine->pid == pid)) 36762306a36Sopenharmony_ci goto out; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if ((pid != HOST_KERNEL_ID) && 37062306a36Sopenharmony_ci (pid != DEFAULT_GUEST_KERNEL_ID) && 37162306a36Sopenharmony_ci (symbol_conf.guestmount)) { 37262306a36Sopenharmony_ci sprintf(path, "%s/%d", symbol_conf.guestmount, pid); 37362306a36Sopenharmony_ci if (access(path, R_OK)) { 37462306a36Sopenharmony_ci static struct strlist *seen; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (!seen) 37762306a36Sopenharmony_ci seen = strlist__new(NULL, NULL); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (!strlist__has_entry(seen, path)) { 38062306a36Sopenharmony_ci pr_err("Can't access file %s\n", path); 38162306a36Sopenharmony_ci strlist__add(seen, path); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci machine = NULL; 38462306a36Sopenharmony_ci goto out; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci root_dir = path; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci machine = machines__add(machines, pid, root_dir); 39062306a36Sopenharmony_ciout: 39162306a36Sopenharmony_ci return machine; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistruct machine *machines__find_guest(struct machines *machines, pid_t pid) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct machine *machine = machines__find(machines, pid); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (!machine) 39962306a36Sopenharmony_ci machine = machines__findnew(machines, DEFAULT_GUEST_KERNEL_ID); 40062306a36Sopenharmony_ci return machine; 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* 40462306a36Sopenharmony_ci * A common case for KVM test programs is that the test program acts as the 40562306a36Sopenharmony_ci * hypervisor, creating, running and destroying the virtual machine, and 40662306a36Sopenharmony_ci * providing the guest object code from its own object code. In this case, 40762306a36Sopenharmony_ci * the VM is not running an OS, but only the functions loaded into it by the 40862306a36Sopenharmony_ci * hypervisor test program, and conveniently, loaded at the same virtual 40962306a36Sopenharmony_ci * addresses. 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * Normally to resolve addresses, MMAP events are needed to map addresses 41262306a36Sopenharmony_ci * back to the object code and debug symbols for that object code. 41362306a36Sopenharmony_ci * 41462306a36Sopenharmony_ci * Currently, there is no way to get such mapping information from guests 41562306a36Sopenharmony_ci * but, in the scenario described above, the guest has the same mappings 41662306a36Sopenharmony_ci * as the hypervisor, so support for that scenario can be achieved. 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * To support that, copy the host thread's maps to the guest thread's maps. 41962306a36Sopenharmony_ci * Note, we do not discover the guest until we encounter a guest event, 42062306a36Sopenharmony_ci * which works well because it is not until then that we know that the host 42162306a36Sopenharmony_ci * thread's maps have been set up. 42262306a36Sopenharmony_ci * 42362306a36Sopenharmony_ci * This function returns the guest thread. Apart from keeping the data 42462306a36Sopenharmony_ci * structures sane, using a thread belonging to the guest machine, instead 42562306a36Sopenharmony_ci * of the host thread, allows it to have its own comm (refer 42662306a36Sopenharmony_ci * thread__set_guest_comm()). 42762306a36Sopenharmony_ci */ 42862306a36Sopenharmony_cistatic struct thread *findnew_guest_code(struct machine *machine, 42962306a36Sopenharmony_ci struct machine *host_machine, 43062306a36Sopenharmony_ci pid_t pid) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci struct thread *host_thread; 43362306a36Sopenharmony_ci struct thread *thread; 43462306a36Sopenharmony_ci int err; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci if (!machine) 43762306a36Sopenharmony_ci return NULL; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci thread = machine__findnew_thread(machine, -1, pid); 44062306a36Sopenharmony_ci if (!thread) 44162306a36Sopenharmony_ci return NULL; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* Assume maps are set up if there are any */ 44462306a36Sopenharmony_ci if (maps__nr_maps(thread__maps(thread))) 44562306a36Sopenharmony_ci return thread; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci host_thread = machine__find_thread(host_machine, -1, pid); 44862306a36Sopenharmony_ci if (!host_thread) 44962306a36Sopenharmony_ci goto out_err; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci thread__set_guest_comm(thread, pid); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* 45462306a36Sopenharmony_ci * Guest code can be found in hypervisor process at the same address 45562306a36Sopenharmony_ci * so copy host maps. 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci err = maps__clone(thread, thread__maps(host_thread)); 45862306a36Sopenharmony_ci thread__put(host_thread); 45962306a36Sopenharmony_ci if (err) 46062306a36Sopenharmony_ci goto out_err; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return thread; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ciout_err: 46562306a36Sopenharmony_ci thread__zput(thread); 46662306a36Sopenharmony_ci return NULL; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistruct thread *machines__findnew_guest_code(struct machines *machines, pid_t pid) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct machine *host_machine = machines__find(machines, HOST_KERNEL_ID); 47262306a36Sopenharmony_ci struct machine *machine = machines__findnew(machines, pid); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return findnew_guest_code(machine, host_machine, pid); 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistruct thread *machine__findnew_guest_code(struct machine *machine, pid_t pid) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct machines *machines = machine->machines; 48062306a36Sopenharmony_ci struct machine *host_machine; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (!machines) 48362306a36Sopenharmony_ci return NULL; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci host_machine = machines__find(machines, HOST_KERNEL_ID); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return findnew_guest_code(machine, host_machine, pid); 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_civoid machines__process_guests(struct machines *machines, 49162306a36Sopenharmony_ci machine__process_t process, void *data) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci struct rb_node *nd; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 49662306a36Sopenharmony_ci struct machine *pos = rb_entry(nd, struct machine, rb_node); 49762306a36Sopenharmony_ci process(pos, data); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_civoid machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct rb_node *node; 50462306a36Sopenharmony_ci struct machine *machine; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci machines->host.id_hdr_size = id_hdr_size; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci for (node = rb_first_cached(&machines->guests); node; 50962306a36Sopenharmony_ci node = rb_next(node)) { 51062306a36Sopenharmony_ci machine = rb_entry(node, struct machine, rb_node); 51162306a36Sopenharmony_ci machine->id_hdr_size = id_hdr_size; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return; 51562306a36Sopenharmony_ci} 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic void machine__update_thread_pid(struct machine *machine, 51862306a36Sopenharmony_ci struct thread *th, pid_t pid) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct thread *leader; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (pid == thread__pid(th) || pid == -1 || thread__pid(th) != -1) 52362306a36Sopenharmony_ci return; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci thread__set_pid(th, pid); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (thread__pid(th) == thread__tid(th)) 52862306a36Sopenharmony_ci return; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci leader = __machine__findnew_thread(machine, thread__pid(th), thread__pid(th)); 53162306a36Sopenharmony_ci if (!leader) 53262306a36Sopenharmony_ci goto out_err; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci if (!thread__maps(leader)) 53562306a36Sopenharmony_ci thread__set_maps(leader, maps__new(machine)); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (!thread__maps(leader)) 53862306a36Sopenharmony_ci goto out_err; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci if (thread__maps(th) == thread__maps(leader)) 54162306a36Sopenharmony_ci goto out_put; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (thread__maps(th)) { 54462306a36Sopenharmony_ci /* 54562306a36Sopenharmony_ci * Maps are created from MMAP events which provide the pid and 54662306a36Sopenharmony_ci * tid. Consequently there never should be any maps on a thread 54762306a36Sopenharmony_ci * with an unknown pid. Just print an error if there are. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ci if (!maps__empty(thread__maps(th))) 55062306a36Sopenharmony_ci pr_err("Discarding thread maps for %d:%d\n", 55162306a36Sopenharmony_ci thread__pid(th), thread__tid(th)); 55262306a36Sopenharmony_ci maps__put(thread__maps(th)); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci thread__set_maps(th, maps__get(thread__maps(leader))); 55662306a36Sopenharmony_ciout_put: 55762306a36Sopenharmony_ci thread__put(leader); 55862306a36Sopenharmony_ci return; 55962306a36Sopenharmony_ciout_err: 56062306a36Sopenharmony_ci pr_err("Failed to join map groups for %d:%d\n", thread__pid(th), thread__tid(th)); 56162306a36Sopenharmony_ci goto out_put; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci/* 56562306a36Sopenharmony_ci * Front-end cache - TID lookups come in blocks, 56662306a36Sopenharmony_ci * so most of the time we dont have to look up 56762306a36Sopenharmony_ci * the full rbtree: 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_cistatic struct thread* 57062306a36Sopenharmony_ci__threads__get_last_match(struct threads *threads, struct machine *machine, 57162306a36Sopenharmony_ci int pid, int tid) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci struct thread *th; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci th = threads->last_match; 57662306a36Sopenharmony_ci if (th != NULL) { 57762306a36Sopenharmony_ci if (thread__tid(th) == tid) { 57862306a36Sopenharmony_ci machine__update_thread_pid(machine, th, pid); 57962306a36Sopenharmony_ci return thread__get(th); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci thread__put(threads->last_match); 58262306a36Sopenharmony_ci threads->last_match = NULL; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return NULL; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_cistatic struct thread* 58962306a36Sopenharmony_cithreads__get_last_match(struct threads *threads, struct machine *machine, 59062306a36Sopenharmony_ci int pid, int tid) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct thread *th = NULL; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (perf_singlethreaded) 59562306a36Sopenharmony_ci th = __threads__get_last_match(threads, machine, pid, tid); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return th; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic void 60162306a36Sopenharmony_ci__threads__set_last_match(struct threads *threads, struct thread *th) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci thread__put(threads->last_match); 60462306a36Sopenharmony_ci threads->last_match = thread__get(th); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void 60862306a36Sopenharmony_cithreads__set_last_match(struct threads *threads, struct thread *th) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci if (perf_singlethreaded) 61162306a36Sopenharmony_ci __threads__set_last_match(threads, th); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* 61562306a36Sopenharmony_ci * Caller must eventually drop thread->refcnt returned with a successful 61662306a36Sopenharmony_ci * lookup/new thread inserted. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic struct thread *____machine__findnew_thread(struct machine *machine, 61962306a36Sopenharmony_ci struct threads *threads, 62062306a36Sopenharmony_ci pid_t pid, pid_t tid, 62162306a36Sopenharmony_ci bool create) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct rb_node **p = &threads->entries.rb_root.rb_node; 62462306a36Sopenharmony_ci struct rb_node *parent = NULL; 62562306a36Sopenharmony_ci struct thread *th; 62662306a36Sopenharmony_ci struct thread_rb_node *nd; 62762306a36Sopenharmony_ci bool leftmost = true; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci th = threads__get_last_match(threads, machine, pid, tid); 63062306a36Sopenharmony_ci if (th) 63162306a36Sopenharmony_ci return th; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci while (*p != NULL) { 63462306a36Sopenharmony_ci parent = *p; 63562306a36Sopenharmony_ci th = rb_entry(parent, struct thread_rb_node, rb_node)->thread; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (thread__tid(th) == tid) { 63862306a36Sopenharmony_ci threads__set_last_match(threads, th); 63962306a36Sopenharmony_ci machine__update_thread_pid(machine, th, pid); 64062306a36Sopenharmony_ci return thread__get(th); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (tid < thread__tid(th)) 64462306a36Sopenharmony_ci p = &(*p)->rb_left; 64562306a36Sopenharmony_ci else { 64662306a36Sopenharmony_ci p = &(*p)->rb_right; 64762306a36Sopenharmony_ci leftmost = false; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (!create) 65262306a36Sopenharmony_ci return NULL; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci th = thread__new(pid, tid); 65562306a36Sopenharmony_ci if (th == NULL) 65662306a36Sopenharmony_ci return NULL; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci nd = malloc(sizeof(*nd)); 65962306a36Sopenharmony_ci if (nd == NULL) { 66062306a36Sopenharmony_ci thread__put(th); 66162306a36Sopenharmony_ci return NULL; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci nd->thread = th; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci rb_link_node(&nd->rb_node, parent, p); 66662306a36Sopenharmony_ci rb_insert_color_cached(&nd->rb_node, &threads->entries, leftmost); 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * We have to initialize maps separately after rb tree is updated. 66962306a36Sopenharmony_ci * 67062306a36Sopenharmony_ci * The reason is that we call machine__findnew_thread within 67162306a36Sopenharmony_ci * thread__init_maps to find the thread leader and that would screwed 67262306a36Sopenharmony_ci * the rb tree. 67362306a36Sopenharmony_ci */ 67462306a36Sopenharmony_ci if (thread__init_maps(th, machine)) { 67562306a36Sopenharmony_ci pr_err("Thread init failed thread %d\n", pid); 67662306a36Sopenharmony_ci rb_erase_cached(&nd->rb_node, &threads->entries); 67762306a36Sopenharmony_ci RB_CLEAR_NODE(&nd->rb_node); 67862306a36Sopenharmony_ci free(nd); 67962306a36Sopenharmony_ci thread__put(th); 68062306a36Sopenharmony_ci return NULL; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci /* 68362306a36Sopenharmony_ci * It is now in the rbtree, get a ref 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_ci threads__set_last_match(threads, th); 68662306a36Sopenharmony_ci ++threads->nr; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci return thread__get(th); 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_cistruct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, pid_t tid) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci return ____machine__findnew_thread(machine, machine__threads(machine, tid), pid, tid, true); 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistruct thread *machine__findnew_thread(struct machine *machine, pid_t pid, 69762306a36Sopenharmony_ci pid_t tid) 69862306a36Sopenharmony_ci{ 69962306a36Sopenharmony_ci struct threads *threads = machine__threads(machine, tid); 70062306a36Sopenharmony_ci struct thread *th; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci down_write(&threads->lock); 70362306a36Sopenharmony_ci th = __machine__findnew_thread(machine, pid, tid); 70462306a36Sopenharmony_ci up_write(&threads->lock); 70562306a36Sopenharmony_ci return th; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistruct thread *machine__find_thread(struct machine *machine, pid_t pid, 70962306a36Sopenharmony_ci pid_t tid) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct threads *threads = machine__threads(machine, tid); 71262306a36Sopenharmony_ci struct thread *th; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci down_read(&threads->lock); 71562306a36Sopenharmony_ci th = ____machine__findnew_thread(machine, threads, pid, tid, false); 71662306a36Sopenharmony_ci up_read(&threads->lock); 71762306a36Sopenharmony_ci return th; 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci/* 72162306a36Sopenharmony_ci * Threads are identified by pid and tid, and the idle task has pid == tid == 0. 72262306a36Sopenharmony_ci * So here a single thread is created for that, but actually there is a separate 72362306a36Sopenharmony_ci * idle task per cpu, so there should be one 'struct thread' per cpu, but there 72462306a36Sopenharmony_ci * is only 1. That causes problems for some tools, requiring workarounds. For 72562306a36Sopenharmony_ci * example get_idle_thread() in builtin-sched.c, or thread_stack__per_cpu(). 72662306a36Sopenharmony_ci */ 72762306a36Sopenharmony_cistruct thread *machine__idle_thread(struct machine *machine) 72862306a36Sopenharmony_ci{ 72962306a36Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, 0, 0); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (!thread || thread__set_comm(thread, "swapper", 0) || 73262306a36Sopenharmony_ci thread__set_namespaces(thread, 0, NULL)) 73362306a36Sopenharmony_ci pr_err("problem inserting idle task for machine pid %d\n", machine->pid); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return thread; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistruct comm *machine__thread_exec_comm(struct machine *machine, 73962306a36Sopenharmony_ci struct thread *thread) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci if (machine->comm_exec) 74262306a36Sopenharmony_ci return thread__exec_comm(thread); 74362306a36Sopenharmony_ci else 74462306a36Sopenharmony_ci return thread__comm(thread); 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ciint machine__process_comm_event(struct machine *machine, union perf_event *event, 74862306a36Sopenharmony_ci struct perf_sample *sample) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, 75162306a36Sopenharmony_ci event->comm.pid, 75262306a36Sopenharmony_ci event->comm.tid); 75362306a36Sopenharmony_ci bool exec = event->header.misc & PERF_RECORD_MISC_COMM_EXEC; 75462306a36Sopenharmony_ci int err = 0; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci if (exec) 75762306a36Sopenharmony_ci machine->comm_exec = true; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (dump_trace) 76062306a36Sopenharmony_ci perf_event__fprintf_comm(event, stdout); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (thread == NULL || 76362306a36Sopenharmony_ci __thread__set_comm(thread, event->comm.comm, sample->time, exec)) { 76462306a36Sopenharmony_ci dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n"); 76562306a36Sopenharmony_ci err = -1; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci thread__put(thread); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return err; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ciint machine__process_namespaces_event(struct machine *machine __maybe_unused, 77462306a36Sopenharmony_ci union perf_event *event, 77562306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct thread *thread = machine__findnew_thread(machine, 77862306a36Sopenharmony_ci event->namespaces.pid, 77962306a36Sopenharmony_ci event->namespaces.tid); 78062306a36Sopenharmony_ci int err = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci WARN_ONCE(event->namespaces.nr_namespaces > NR_NAMESPACES, 78362306a36Sopenharmony_ci "\nWARNING: kernel seems to support more namespaces than perf" 78462306a36Sopenharmony_ci " tool.\nTry updating the perf tool..\n\n"); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci WARN_ONCE(event->namespaces.nr_namespaces < NR_NAMESPACES, 78762306a36Sopenharmony_ci "\nWARNING: perf tool seems to support more namespaces than" 78862306a36Sopenharmony_ci " the kernel.\nTry updating the kernel..\n\n"); 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (dump_trace) 79162306a36Sopenharmony_ci perf_event__fprintf_namespaces(event, stdout); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci if (thread == NULL || 79462306a36Sopenharmony_ci thread__set_namespaces(thread, sample->time, &event->namespaces)) { 79562306a36Sopenharmony_ci dump_printf("problem processing PERF_RECORD_NAMESPACES, skipping event.\n"); 79662306a36Sopenharmony_ci err = -1; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci thread__put(thread); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return err; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ciint machine__process_cgroup_event(struct machine *machine, 80562306a36Sopenharmony_ci union perf_event *event, 80662306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct cgroup *cgrp; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (dump_trace) 81162306a36Sopenharmony_ci perf_event__fprintf_cgroup(event, stdout); 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci cgrp = cgroup__findnew(machine->env, event->cgroup.id, event->cgroup.path); 81462306a36Sopenharmony_ci if (cgrp == NULL) 81562306a36Sopenharmony_ci return -ENOMEM; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return 0; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ciint machine__process_lost_event(struct machine *machine __maybe_unused, 82162306a36Sopenharmony_ci union perf_event *event, struct perf_sample *sample __maybe_unused) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci dump_printf(": id:%" PRI_lu64 ": lost:%" PRI_lu64 "\n", 82462306a36Sopenharmony_ci event->lost.id, event->lost.lost); 82562306a36Sopenharmony_ci return 0; 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ciint machine__process_lost_samples_event(struct machine *machine __maybe_unused, 82962306a36Sopenharmony_ci union perf_event *event, struct perf_sample *sample) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci dump_printf(": id:%" PRIu64 ": lost samples :%" PRI_lu64 "\n", 83262306a36Sopenharmony_ci sample->id, event->lost_samples.lost); 83362306a36Sopenharmony_ci return 0; 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_cistatic struct dso *machine__findnew_module_dso(struct machine *machine, 83762306a36Sopenharmony_ci struct kmod_path *m, 83862306a36Sopenharmony_ci const char *filename) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct dso *dso; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci down_write(&machine->dsos.lock); 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci dso = __dsos__find(&machine->dsos, m->name, true); 84562306a36Sopenharmony_ci if (!dso) { 84662306a36Sopenharmony_ci dso = __dsos__addnew(&machine->dsos, m->name); 84762306a36Sopenharmony_ci if (dso == NULL) 84862306a36Sopenharmony_ci goto out_unlock; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci dso__set_module_info(dso, m, machine); 85162306a36Sopenharmony_ci dso__set_long_name(dso, strdup(filename), true); 85262306a36Sopenharmony_ci dso->kernel = DSO_SPACE__KERNEL; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci dso__get(dso); 85662306a36Sopenharmony_ciout_unlock: 85762306a36Sopenharmony_ci up_write(&machine->dsos.lock); 85862306a36Sopenharmony_ci return dso; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ciint machine__process_aux_event(struct machine *machine __maybe_unused, 86262306a36Sopenharmony_ci union perf_event *event) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci if (dump_trace) 86562306a36Sopenharmony_ci perf_event__fprintf_aux(event, stdout); 86662306a36Sopenharmony_ci return 0; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ciint machine__process_itrace_start_event(struct machine *machine __maybe_unused, 87062306a36Sopenharmony_ci union perf_event *event) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci if (dump_trace) 87362306a36Sopenharmony_ci perf_event__fprintf_itrace_start(event, stdout); 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ciint machine__process_aux_output_hw_id_event(struct machine *machine __maybe_unused, 87862306a36Sopenharmony_ci union perf_event *event) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci if (dump_trace) 88162306a36Sopenharmony_ci perf_event__fprintf_aux_output_hw_id(event, stdout); 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ciint machine__process_switch_event(struct machine *machine __maybe_unused, 88662306a36Sopenharmony_ci union perf_event *event) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci if (dump_trace) 88962306a36Sopenharmony_ci perf_event__fprintf_switch(event, stdout); 89062306a36Sopenharmony_ci return 0; 89162306a36Sopenharmony_ci} 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_cistatic int machine__process_ksymbol_register(struct machine *machine, 89462306a36Sopenharmony_ci union perf_event *event, 89562306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused) 89662306a36Sopenharmony_ci{ 89762306a36Sopenharmony_ci struct symbol *sym; 89862306a36Sopenharmony_ci struct dso *dso; 89962306a36Sopenharmony_ci struct map *map = maps__find(machine__kernel_maps(machine), event->ksymbol.addr); 90062306a36Sopenharmony_ci bool put_map = false; 90162306a36Sopenharmony_ci int err = 0; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci if (!map) { 90462306a36Sopenharmony_ci dso = dso__new(event->ksymbol.name); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci if (!dso) { 90762306a36Sopenharmony_ci err = -ENOMEM; 90862306a36Sopenharmony_ci goto out; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci dso->kernel = DSO_SPACE__KERNEL; 91162306a36Sopenharmony_ci map = map__new2(0, dso); 91262306a36Sopenharmony_ci dso__put(dso); 91362306a36Sopenharmony_ci if (!map) { 91462306a36Sopenharmony_ci err = -ENOMEM; 91562306a36Sopenharmony_ci goto out; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci /* 91862306a36Sopenharmony_ci * The inserted map has a get on it, we need to put to release 91962306a36Sopenharmony_ci * the reference count here, but do it after all accesses are 92062306a36Sopenharmony_ci * done. 92162306a36Sopenharmony_ci */ 92262306a36Sopenharmony_ci put_map = true; 92362306a36Sopenharmony_ci if (event->ksymbol.ksym_type == PERF_RECORD_KSYMBOL_TYPE_OOL) { 92462306a36Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__OOL; 92562306a36Sopenharmony_ci dso->data.file_size = event->ksymbol.len; 92662306a36Sopenharmony_ci dso__set_loaded(dso); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci map__set_start(map, event->ksymbol.addr); 93062306a36Sopenharmony_ci map__set_end(map, map__start(map) + event->ksymbol.len); 93162306a36Sopenharmony_ci err = maps__insert(machine__kernel_maps(machine), map); 93262306a36Sopenharmony_ci if (err) { 93362306a36Sopenharmony_ci err = -ENOMEM; 93462306a36Sopenharmony_ci goto out; 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci dso__set_loaded(dso); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (is_bpf_image(event->ksymbol.name)) { 94062306a36Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__BPF_IMAGE; 94162306a36Sopenharmony_ci dso__set_long_name(dso, "", false); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci } else { 94462306a36Sopenharmony_ci dso = map__dso(map); 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci sym = symbol__new(map__map_ip(map, map__start(map)), 94862306a36Sopenharmony_ci event->ksymbol.len, 94962306a36Sopenharmony_ci 0, 0, event->ksymbol.name); 95062306a36Sopenharmony_ci if (!sym) { 95162306a36Sopenharmony_ci err = -ENOMEM; 95262306a36Sopenharmony_ci goto out; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci dso__insert_symbol(dso, sym); 95562306a36Sopenharmony_ciout: 95662306a36Sopenharmony_ci if (put_map) 95762306a36Sopenharmony_ci map__put(map); 95862306a36Sopenharmony_ci return err; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_cistatic int machine__process_ksymbol_unregister(struct machine *machine, 96262306a36Sopenharmony_ci union perf_event *event, 96362306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct symbol *sym; 96662306a36Sopenharmony_ci struct map *map; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci map = maps__find(machine__kernel_maps(machine), event->ksymbol.addr); 96962306a36Sopenharmony_ci if (!map) 97062306a36Sopenharmony_ci return 0; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci if (RC_CHK_ACCESS(map) != RC_CHK_ACCESS(machine->vmlinux_map)) 97362306a36Sopenharmony_ci maps__remove(machine__kernel_maps(machine), map); 97462306a36Sopenharmony_ci else { 97562306a36Sopenharmony_ci struct dso *dso = map__dso(map); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci sym = dso__find_symbol(dso, map__map_ip(map, map__start(map))); 97862306a36Sopenharmony_ci if (sym) 97962306a36Sopenharmony_ci dso__delete_symbol(dso, sym); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci return 0; 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ciint machine__process_ksymbol(struct machine *machine __maybe_unused, 98662306a36Sopenharmony_ci union perf_event *event, 98762306a36Sopenharmony_ci struct perf_sample *sample) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci if (dump_trace) 99062306a36Sopenharmony_ci perf_event__fprintf_ksymbol(event, stdout); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (event->ksymbol.flags & PERF_RECORD_KSYMBOL_FLAGS_UNREGISTER) 99362306a36Sopenharmony_ci return machine__process_ksymbol_unregister(machine, event, 99462306a36Sopenharmony_ci sample); 99562306a36Sopenharmony_ci return machine__process_ksymbol_register(machine, event, sample); 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ciint machine__process_text_poke(struct machine *machine, union perf_event *event, 99962306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct map *map = maps__find(machine__kernel_maps(machine), event->text_poke.addr); 100262306a36Sopenharmony_ci u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 100362306a36Sopenharmony_ci struct dso *dso = map ? map__dso(map) : NULL; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (dump_trace) 100662306a36Sopenharmony_ci perf_event__fprintf_text_poke(event, machine, stdout); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (!event->text_poke.new_len) 100962306a36Sopenharmony_ci return 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (cpumode != PERF_RECORD_MISC_KERNEL) { 101262306a36Sopenharmony_ci pr_debug("%s: unsupported cpumode - ignoring\n", __func__); 101362306a36Sopenharmony_ci return 0; 101462306a36Sopenharmony_ci } 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci if (dso) { 101762306a36Sopenharmony_ci u8 *new_bytes = event->text_poke.bytes + event->text_poke.old_len; 101862306a36Sopenharmony_ci int ret; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* 102162306a36Sopenharmony_ci * Kernel maps might be changed when loading symbols so loading 102262306a36Sopenharmony_ci * must be done prior to using kernel maps. 102362306a36Sopenharmony_ci */ 102462306a36Sopenharmony_ci map__load(map); 102562306a36Sopenharmony_ci ret = dso__data_write_cache_addr(dso, map, machine, 102662306a36Sopenharmony_ci event->text_poke.addr, 102762306a36Sopenharmony_ci new_bytes, 102862306a36Sopenharmony_ci event->text_poke.new_len); 102962306a36Sopenharmony_ci if (ret != event->text_poke.new_len) 103062306a36Sopenharmony_ci pr_debug("Failed to write kernel text poke at %#" PRI_lx64 "\n", 103162306a36Sopenharmony_ci event->text_poke.addr); 103262306a36Sopenharmony_ci } else { 103362306a36Sopenharmony_ci pr_debug("Failed to find kernel text poke address map for %#" PRI_lx64 "\n", 103462306a36Sopenharmony_ci event->text_poke.addr); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_cistatic struct map *machine__addnew_module_map(struct machine *machine, u64 start, 104162306a36Sopenharmony_ci const char *filename) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct map *map = NULL; 104462306a36Sopenharmony_ci struct kmod_path m; 104562306a36Sopenharmony_ci struct dso *dso; 104662306a36Sopenharmony_ci int err; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci if (kmod_path__parse_name(&m, filename)) 104962306a36Sopenharmony_ci return NULL; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci dso = machine__findnew_module_dso(machine, &m, filename); 105262306a36Sopenharmony_ci if (dso == NULL) 105362306a36Sopenharmony_ci goto out; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci map = map__new2(start, dso); 105662306a36Sopenharmony_ci if (map == NULL) 105762306a36Sopenharmony_ci goto out; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci err = maps__insert(machine__kernel_maps(machine), map); 106062306a36Sopenharmony_ci /* If maps__insert failed, return NULL. */ 106162306a36Sopenharmony_ci if (err) { 106262306a36Sopenharmony_ci map__put(map); 106362306a36Sopenharmony_ci map = NULL; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ciout: 106662306a36Sopenharmony_ci /* put the dso here, corresponding to machine__findnew_module_dso */ 106762306a36Sopenharmony_ci dso__put(dso); 106862306a36Sopenharmony_ci zfree(&m.name); 106962306a36Sopenharmony_ci return map; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cisize_t machines__fprintf_dsos(struct machines *machines, FILE *fp) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci struct rb_node *nd; 107562306a36Sopenharmony_ci size_t ret = __dsos__fprintf(&machines->host.dsos.head, fp); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 107862306a36Sopenharmony_ci struct machine *pos = rb_entry(nd, struct machine, rb_node); 107962306a36Sopenharmony_ci ret += __dsos__fprintf(&pos->dsos.head, fp); 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci return ret; 108362306a36Sopenharmony_ci} 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cisize_t machine__fprintf_dsos_buildid(struct machine *m, FILE *fp, 108662306a36Sopenharmony_ci bool (skip)(struct dso *dso, int parm), int parm) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci return __dsos__fprintf_buildid(&m->dsos.head, fp, skip, parm); 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_cisize_t machines__fprintf_dsos_buildid(struct machines *machines, FILE *fp, 109262306a36Sopenharmony_ci bool (skip)(struct dso *dso, int parm), int parm) 109362306a36Sopenharmony_ci{ 109462306a36Sopenharmony_ci struct rb_node *nd; 109562306a36Sopenharmony_ci size_t ret = machine__fprintf_dsos_buildid(&machines->host, fp, skip, parm); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 109862306a36Sopenharmony_ci struct machine *pos = rb_entry(nd, struct machine, rb_node); 109962306a36Sopenharmony_ci ret += machine__fprintf_dsos_buildid(pos, fp, skip, parm); 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci return ret; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cisize_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci int i; 110762306a36Sopenharmony_ci size_t printed = 0; 110862306a36Sopenharmony_ci struct dso *kdso = machine__kernel_dso(machine); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (kdso->has_build_id) { 111162306a36Sopenharmony_ci char filename[PATH_MAX]; 111262306a36Sopenharmony_ci if (dso__build_id_filename(kdso, filename, sizeof(filename), 111362306a36Sopenharmony_ci false)) 111462306a36Sopenharmony_ci printed += fprintf(fp, "[0] %s\n", filename); 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci for (i = 0; i < vmlinux_path__nr_entries; ++i) 111862306a36Sopenharmony_ci printed += fprintf(fp, "[%d] %s\n", 111962306a36Sopenharmony_ci i + kdso->has_build_id, vmlinux_path[i]); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci return printed; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cisize_t machine__fprintf(struct machine *machine, FILE *fp) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct rb_node *nd; 112762306a36Sopenharmony_ci size_t ret; 112862306a36Sopenharmony_ci int i; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 113162306a36Sopenharmony_ci struct threads *threads = &machine->threads[i]; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci down_read(&threads->lock); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci ret = fprintf(fp, "Threads: %u\n", threads->nr); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci for (nd = rb_first_cached(&threads->entries); nd; 113862306a36Sopenharmony_ci nd = rb_next(nd)) { 113962306a36Sopenharmony_ci struct thread *pos = rb_entry(nd, struct thread_rb_node, rb_node)->thread; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci ret += thread__fprintf(pos, fp); 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci up_read(&threads->lock); 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci return ret; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic struct dso *machine__get_kernel(struct machine *machine) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci const char *vmlinux_name = machine->mmap_name; 115262306a36Sopenharmony_ci struct dso *kernel; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (machine__is_host(machine)) { 115562306a36Sopenharmony_ci if (symbol_conf.vmlinux_name) 115662306a36Sopenharmony_ci vmlinux_name = symbol_conf.vmlinux_name; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci kernel = machine__findnew_kernel(machine, vmlinux_name, 115962306a36Sopenharmony_ci "[kernel]", DSO_SPACE__KERNEL); 116062306a36Sopenharmony_ci } else { 116162306a36Sopenharmony_ci if (symbol_conf.default_guest_vmlinux_name) 116262306a36Sopenharmony_ci vmlinux_name = symbol_conf.default_guest_vmlinux_name; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci kernel = machine__findnew_kernel(machine, vmlinux_name, 116562306a36Sopenharmony_ci "[guest.kernel]", 116662306a36Sopenharmony_ci DSO_SPACE__KERNEL_GUEST); 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci if (kernel != NULL && (!kernel->has_build_id)) 117062306a36Sopenharmony_ci dso__read_running_kernel_build_id(kernel, machine); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci return kernel; 117362306a36Sopenharmony_ci} 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_civoid machine__get_kallsyms_filename(struct machine *machine, char *buf, 117662306a36Sopenharmony_ci size_t bufsz) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci if (machine__is_default_guest(machine)) 117962306a36Sopenharmony_ci scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms); 118062306a36Sopenharmony_ci else 118162306a36Sopenharmony_ci scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir); 118262306a36Sopenharmony_ci} 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ciconst char *ref_reloc_sym_names[] = {"_text", "_stext", NULL}; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci/* Figure out the start address of kernel map from /proc/kallsyms. 118762306a36Sopenharmony_ci * Returns the name of the start symbol in *symbol_name. Pass in NULL as 118862306a36Sopenharmony_ci * symbol_name if it's not that important. 118962306a36Sopenharmony_ci */ 119062306a36Sopenharmony_cistatic int machine__get_running_kernel_start(struct machine *machine, 119162306a36Sopenharmony_ci const char **symbol_name, 119262306a36Sopenharmony_ci u64 *start, u64 *end) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci char filename[PATH_MAX]; 119562306a36Sopenharmony_ci int i, err = -1; 119662306a36Sopenharmony_ci const char *name; 119762306a36Sopenharmony_ci u64 addr = 0; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci machine__get_kallsyms_filename(machine, filename, PATH_MAX); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (symbol__restricted_filename(filename, "/proc/kallsyms")) 120262306a36Sopenharmony_ci return 0; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) { 120562306a36Sopenharmony_ci err = kallsyms__get_function_start(filename, name, &addr); 120662306a36Sopenharmony_ci if (!err) 120762306a36Sopenharmony_ci break; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci if (err) 121162306a36Sopenharmony_ci return -1; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci if (symbol_name) 121462306a36Sopenharmony_ci *symbol_name = name; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci *start = addr; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci err = kallsyms__get_symbol_start(filename, "_edata", &addr); 121962306a36Sopenharmony_ci if (err) 122062306a36Sopenharmony_ci err = kallsyms__get_function_start(filename, "_etext", &addr); 122162306a36Sopenharmony_ci if (!err) 122262306a36Sopenharmony_ci *end = addr; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci return 0; 122562306a36Sopenharmony_ci} 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ciint machine__create_extra_kernel_map(struct machine *machine, 122862306a36Sopenharmony_ci struct dso *kernel, 122962306a36Sopenharmony_ci struct extra_kernel_map *xm) 123062306a36Sopenharmony_ci{ 123162306a36Sopenharmony_ci struct kmap *kmap; 123262306a36Sopenharmony_ci struct map *map; 123362306a36Sopenharmony_ci int err; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci map = map__new2(xm->start, kernel); 123662306a36Sopenharmony_ci if (!map) 123762306a36Sopenharmony_ci return -ENOMEM; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci map__set_end(map, xm->end); 124062306a36Sopenharmony_ci map__set_pgoff(map, xm->pgoff); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci kmap = map__kmap(map); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci strlcpy(kmap->name, xm->name, KMAP_NAME_LEN); 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci err = maps__insert(machine__kernel_maps(machine), map); 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci if (!err) { 124962306a36Sopenharmony_ci pr_debug2("Added extra kernel map %s %" PRIx64 "-%" PRIx64 "\n", 125062306a36Sopenharmony_ci kmap->name, map__start(map), map__end(map)); 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci map__put(map); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci return err; 125662306a36Sopenharmony_ci} 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_cistatic u64 find_entry_trampoline(struct dso *dso) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci /* Duplicates are removed so lookup all aliases */ 126162306a36Sopenharmony_ci const char *syms[] = { 126262306a36Sopenharmony_ci "_entry_trampoline", 126362306a36Sopenharmony_ci "__entry_trampoline_start", 126462306a36Sopenharmony_ci "entry_SYSCALL_64_trampoline", 126562306a36Sopenharmony_ci }; 126662306a36Sopenharmony_ci struct symbol *sym = dso__first_symbol(dso); 126762306a36Sopenharmony_ci unsigned int i; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci for (; sym; sym = dso__next_symbol(sym)) { 127062306a36Sopenharmony_ci if (sym->binding != STB_GLOBAL) 127162306a36Sopenharmony_ci continue; 127262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(syms); i++) { 127362306a36Sopenharmony_ci if (!strcmp(sym->name, syms[i])) 127462306a36Sopenharmony_ci return sym->start; 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci return 0; 127962306a36Sopenharmony_ci} 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci/* 128262306a36Sopenharmony_ci * These values can be used for kernels that do not have symbols for the entry 128362306a36Sopenharmony_ci * trampolines in kallsyms. 128462306a36Sopenharmony_ci */ 128562306a36Sopenharmony_ci#define X86_64_CPU_ENTRY_AREA_PER_CPU 0xfffffe0000000000ULL 128662306a36Sopenharmony_ci#define X86_64_CPU_ENTRY_AREA_SIZE 0x2c000 128762306a36Sopenharmony_ci#define X86_64_ENTRY_TRAMPOLINE 0x6000 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci/* Map x86_64 PTI entry trampolines */ 129062306a36Sopenharmony_ciint machine__map_x86_64_entry_trampolines(struct machine *machine, 129162306a36Sopenharmony_ci struct dso *kernel) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci struct maps *kmaps = machine__kernel_maps(machine); 129462306a36Sopenharmony_ci int nr_cpus_avail, cpu; 129562306a36Sopenharmony_ci bool found = false; 129662306a36Sopenharmony_ci struct map_rb_node *rb_node; 129762306a36Sopenharmony_ci u64 pgoff; 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci /* 130062306a36Sopenharmony_ci * In the vmlinux case, pgoff is a virtual address which must now be 130162306a36Sopenharmony_ci * mapped to a vmlinux offset. 130262306a36Sopenharmony_ci */ 130362306a36Sopenharmony_ci maps__for_each_entry(kmaps, rb_node) { 130462306a36Sopenharmony_ci struct map *dest_map, *map = rb_node->map; 130562306a36Sopenharmony_ci struct kmap *kmap = __map__kmap(map); 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci if (!kmap || !is_entry_trampoline(kmap->name)) 130862306a36Sopenharmony_ci continue; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci dest_map = maps__find(kmaps, map__pgoff(map)); 131162306a36Sopenharmony_ci if (dest_map != map) 131262306a36Sopenharmony_ci map__set_pgoff(map, map__map_ip(dest_map, map__pgoff(map))); 131362306a36Sopenharmony_ci found = true; 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci if (found || machine->trampolines_mapped) 131662306a36Sopenharmony_ci return 0; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci pgoff = find_entry_trampoline(kernel); 131962306a36Sopenharmony_ci if (!pgoff) 132062306a36Sopenharmony_ci return 0; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci nr_cpus_avail = machine__nr_cpus_avail(machine); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci /* Add a 1 page map for each CPU's entry trampoline */ 132562306a36Sopenharmony_ci for (cpu = 0; cpu < nr_cpus_avail; cpu++) { 132662306a36Sopenharmony_ci u64 va = X86_64_CPU_ENTRY_AREA_PER_CPU + 132762306a36Sopenharmony_ci cpu * X86_64_CPU_ENTRY_AREA_SIZE + 132862306a36Sopenharmony_ci X86_64_ENTRY_TRAMPOLINE; 132962306a36Sopenharmony_ci struct extra_kernel_map xm = { 133062306a36Sopenharmony_ci .start = va, 133162306a36Sopenharmony_ci .end = va + page_size, 133262306a36Sopenharmony_ci .pgoff = pgoff, 133362306a36Sopenharmony_ci }; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci strlcpy(xm.name, ENTRY_TRAMPOLINE_NAME, KMAP_NAME_LEN); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (machine__create_extra_kernel_map(machine, kernel, &xm) < 0) 133862306a36Sopenharmony_ci return -1; 133962306a36Sopenharmony_ci } 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci machine->trampolines_mapped = nr_cpus_avail; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci return 0; 134462306a36Sopenharmony_ci} 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ciint __weak machine__create_extra_kernel_maps(struct machine *machine __maybe_unused, 134762306a36Sopenharmony_ci struct dso *kernel __maybe_unused) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci return 0; 135062306a36Sopenharmony_ci} 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_cistatic int 135362306a36Sopenharmony_ci__machine__create_kernel_maps(struct machine *machine, struct dso *kernel) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci /* In case of renewal the kernel map, destroy previous one */ 135662306a36Sopenharmony_ci machine__destroy_kernel_maps(machine); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci map__put(machine->vmlinux_map); 135962306a36Sopenharmony_ci machine->vmlinux_map = map__new2(0, kernel); 136062306a36Sopenharmony_ci if (machine->vmlinux_map == NULL) 136162306a36Sopenharmony_ci return -ENOMEM; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci map__set_map_ip(machine->vmlinux_map, identity__map_ip); 136462306a36Sopenharmony_ci map__set_unmap_ip(machine->vmlinux_map, identity__map_ip); 136562306a36Sopenharmony_ci return maps__insert(machine__kernel_maps(machine), machine->vmlinux_map); 136662306a36Sopenharmony_ci} 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_civoid machine__destroy_kernel_maps(struct machine *machine) 136962306a36Sopenharmony_ci{ 137062306a36Sopenharmony_ci struct kmap *kmap; 137162306a36Sopenharmony_ci struct map *map = machine__kernel_map(machine); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (map == NULL) 137462306a36Sopenharmony_ci return; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci kmap = map__kmap(map); 137762306a36Sopenharmony_ci maps__remove(machine__kernel_maps(machine), map); 137862306a36Sopenharmony_ci if (kmap && kmap->ref_reloc_sym) { 137962306a36Sopenharmony_ci zfree((char **)&kmap->ref_reloc_sym->name); 138062306a36Sopenharmony_ci zfree(&kmap->ref_reloc_sym); 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci map__zput(machine->vmlinux_map); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ciint machines__create_guest_kernel_maps(struct machines *machines) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci int ret = 0; 138962306a36Sopenharmony_ci struct dirent **namelist = NULL; 139062306a36Sopenharmony_ci int i, items = 0; 139162306a36Sopenharmony_ci char path[PATH_MAX]; 139262306a36Sopenharmony_ci pid_t pid; 139362306a36Sopenharmony_ci char *endp; 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci if (symbol_conf.default_guest_vmlinux_name || 139662306a36Sopenharmony_ci symbol_conf.default_guest_modules || 139762306a36Sopenharmony_ci symbol_conf.default_guest_kallsyms) { 139862306a36Sopenharmony_ci machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci if (symbol_conf.guestmount) { 140262306a36Sopenharmony_ci items = scandir(symbol_conf.guestmount, &namelist, NULL, NULL); 140362306a36Sopenharmony_ci if (items <= 0) 140462306a36Sopenharmony_ci return -ENOENT; 140562306a36Sopenharmony_ci for (i = 0; i < items; i++) { 140662306a36Sopenharmony_ci if (!isdigit(namelist[i]->d_name[0])) { 140762306a36Sopenharmony_ci /* Filter out . and .. */ 140862306a36Sopenharmony_ci continue; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci pid = (pid_t)strtol(namelist[i]->d_name, &endp, 10); 141162306a36Sopenharmony_ci if ((*endp != '\0') || 141262306a36Sopenharmony_ci (endp == namelist[i]->d_name) || 141362306a36Sopenharmony_ci (errno == ERANGE)) { 141462306a36Sopenharmony_ci pr_debug("invalid directory (%s). Skipping.\n", 141562306a36Sopenharmony_ci namelist[i]->d_name); 141662306a36Sopenharmony_ci continue; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci sprintf(path, "%s/%s/proc/kallsyms", 141962306a36Sopenharmony_ci symbol_conf.guestmount, 142062306a36Sopenharmony_ci namelist[i]->d_name); 142162306a36Sopenharmony_ci ret = access(path, R_OK); 142262306a36Sopenharmony_ci if (ret) { 142362306a36Sopenharmony_ci pr_debug("Can't access file %s\n", path); 142462306a36Sopenharmony_ci goto failure; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci machines__create_kernel_maps(machines, pid); 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_cifailure: 142962306a36Sopenharmony_ci free(namelist); 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci return ret; 143362306a36Sopenharmony_ci} 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_civoid machines__destroy_kernel_maps(struct machines *machines) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct rb_node *next = rb_first_cached(&machines->guests); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci machine__destroy_kernel_maps(&machines->host); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci while (next) { 144262306a36Sopenharmony_ci struct machine *pos = rb_entry(next, struct machine, rb_node); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci next = rb_next(&pos->rb_node); 144562306a36Sopenharmony_ci rb_erase_cached(&pos->rb_node, &machines->guests); 144662306a36Sopenharmony_ci machine__delete(pos); 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci} 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ciint machines__create_kernel_maps(struct machines *machines, pid_t pid) 145162306a36Sopenharmony_ci{ 145262306a36Sopenharmony_ci struct machine *machine = machines__findnew(machines, pid); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci if (machine == NULL) 145562306a36Sopenharmony_ci return -1; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci return machine__create_kernel_maps(machine); 145862306a36Sopenharmony_ci} 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ciint machine__load_kallsyms(struct machine *machine, const char *filename) 146162306a36Sopenharmony_ci{ 146262306a36Sopenharmony_ci struct map *map = machine__kernel_map(machine); 146362306a36Sopenharmony_ci struct dso *dso = map__dso(map); 146462306a36Sopenharmony_ci int ret = __dso__load_kallsyms(dso, filename, map, true); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci if (ret > 0) { 146762306a36Sopenharmony_ci dso__set_loaded(dso); 146862306a36Sopenharmony_ci /* 146962306a36Sopenharmony_ci * Since /proc/kallsyms will have multiple sessions for the 147062306a36Sopenharmony_ci * kernel, with modules between them, fixup the end of all 147162306a36Sopenharmony_ci * sections. 147262306a36Sopenharmony_ci */ 147362306a36Sopenharmony_ci maps__fixup_end(machine__kernel_maps(machine)); 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci return ret; 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ciint machine__load_vmlinux_path(struct machine *machine) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci struct map *map = machine__kernel_map(machine); 148262306a36Sopenharmony_ci struct dso *dso = map__dso(map); 148362306a36Sopenharmony_ci int ret = dso__load_vmlinux_path(dso, map); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci if (ret > 0) 148662306a36Sopenharmony_ci dso__set_loaded(dso); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci return ret; 148962306a36Sopenharmony_ci} 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_cistatic char *get_kernel_version(const char *root_dir) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci char version[PATH_MAX]; 149462306a36Sopenharmony_ci FILE *file; 149562306a36Sopenharmony_ci char *name, *tmp; 149662306a36Sopenharmony_ci const char *prefix = "Linux version "; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci sprintf(version, "%s/proc/version", root_dir); 149962306a36Sopenharmony_ci file = fopen(version, "r"); 150062306a36Sopenharmony_ci if (!file) 150162306a36Sopenharmony_ci return NULL; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci tmp = fgets(version, sizeof(version), file); 150462306a36Sopenharmony_ci fclose(file); 150562306a36Sopenharmony_ci if (!tmp) 150662306a36Sopenharmony_ci return NULL; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci name = strstr(version, prefix); 150962306a36Sopenharmony_ci if (!name) 151062306a36Sopenharmony_ci return NULL; 151162306a36Sopenharmony_ci name += strlen(prefix); 151262306a36Sopenharmony_ci tmp = strchr(name, ' '); 151362306a36Sopenharmony_ci if (tmp) 151462306a36Sopenharmony_ci *tmp = '\0'; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci return strdup(name); 151762306a36Sopenharmony_ci} 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_cistatic bool is_kmod_dso(struct dso *dso) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE || 152262306a36Sopenharmony_ci dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE; 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_cistatic int maps__set_module_path(struct maps *maps, const char *path, struct kmod_path *m) 152662306a36Sopenharmony_ci{ 152762306a36Sopenharmony_ci char *long_name; 152862306a36Sopenharmony_ci struct dso *dso; 152962306a36Sopenharmony_ci struct map *map = maps__find_by_name(maps, m->name); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (map == NULL) 153262306a36Sopenharmony_ci return 0; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci long_name = strdup(path); 153562306a36Sopenharmony_ci if (long_name == NULL) 153662306a36Sopenharmony_ci return -ENOMEM; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci dso = map__dso(map); 153962306a36Sopenharmony_ci dso__set_long_name(dso, long_name, true); 154062306a36Sopenharmony_ci dso__kernel_module_get_build_id(dso, ""); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci /* 154362306a36Sopenharmony_ci * Full name could reveal us kmod compression, so 154462306a36Sopenharmony_ci * we need to update the symtab_type if needed. 154562306a36Sopenharmony_ci */ 154662306a36Sopenharmony_ci if (m->comp && is_kmod_dso(dso)) { 154762306a36Sopenharmony_ci dso->symtab_type++; 154862306a36Sopenharmony_ci dso->comp = m->comp; 154962306a36Sopenharmony_ci } 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci return 0; 155262306a36Sopenharmony_ci} 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_cistatic int maps__set_modules_path_dir(struct maps *maps, const char *dir_name, int depth) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci struct dirent *dent; 155762306a36Sopenharmony_ci DIR *dir = opendir(dir_name); 155862306a36Sopenharmony_ci int ret = 0; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (!dir) { 156162306a36Sopenharmony_ci pr_debug("%s: cannot open %s dir\n", __func__, dir_name); 156262306a36Sopenharmony_ci return -1; 156362306a36Sopenharmony_ci } 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci while ((dent = readdir(dir)) != NULL) { 156662306a36Sopenharmony_ci char path[PATH_MAX]; 156762306a36Sopenharmony_ci struct stat st; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci /*sshfs might return bad dent->d_type, so we have to stat*/ 157062306a36Sopenharmony_ci path__join(path, sizeof(path), dir_name, dent->d_name); 157162306a36Sopenharmony_ci if (stat(path, &st)) 157262306a36Sopenharmony_ci continue; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci if (S_ISDIR(st.st_mode)) { 157562306a36Sopenharmony_ci if (!strcmp(dent->d_name, ".") || 157662306a36Sopenharmony_ci !strcmp(dent->d_name, "..")) 157762306a36Sopenharmony_ci continue; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci /* Do not follow top-level source and build symlinks */ 158062306a36Sopenharmony_ci if (depth == 0) { 158162306a36Sopenharmony_ci if (!strcmp(dent->d_name, "source") || 158262306a36Sopenharmony_ci !strcmp(dent->d_name, "build")) 158362306a36Sopenharmony_ci continue; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci ret = maps__set_modules_path_dir(maps, path, depth + 1); 158762306a36Sopenharmony_ci if (ret < 0) 158862306a36Sopenharmony_ci goto out; 158962306a36Sopenharmony_ci } else { 159062306a36Sopenharmony_ci struct kmod_path m; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci ret = kmod_path__parse_name(&m, dent->d_name); 159362306a36Sopenharmony_ci if (ret) 159462306a36Sopenharmony_ci goto out; 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci if (m.kmod) 159762306a36Sopenharmony_ci ret = maps__set_module_path(maps, path, &m); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci zfree(&m.name); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci if (ret) 160262306a36Sopenharmony_ci goto out; 160362306a36Sopenharmony_ci } 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ciout: 160762306a36Sopenharmony_ci closedir(dir); 160862306a36Sopenharmony_ci return ret; 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic int machine__set_modules_path(struct machine *machine) 161262306a36Sopenharmony_ci{ 161362306a36Sopenharmony_ci char *version; 161462306a36Sopenharmony_ci char modules_path[PATH_MAX]; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci version = get_kernel_version(machine->root_dir); 161762306a36Sopenharmony_ci if (!version) 161862306a36Sopenharmony_ci return -1; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s", 162162306a36Sopenharmony_ci machine->root_dir, version); 162262306a36Sopenharmony_ci free(version); 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci return maps__set_modules_path_dir(machine__kernel_maps(machine), modules_path, 0); 162562306a36Sopenharmony_ci} 162662306a36Sopenharmony_ciint __weak arch__fix_module_text_start(u64 *start __maybe_unused, 162762306a36Sopenharmony_ci u64 *size __maybe_unused, 162862306a36Sopenharmony_ci const char *name __maybe_unused) 162962306a36Sopenharmony_ci{ 163062306a36Sopenharmony_ci return 0; 163162306a36Sopenharmony_ci} 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_cistatic int machine__create_module(void *arg, const char *name, u64 start, 163462306a36Sopenharmony_ci u64 size) 163562306a36Sopenharmony_ci{ 163662306a36Sopenharmony_ci struct machine *machine = arg; 163762306a36Sopenharmony_ci struct map *map; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci if (arch__fix_module_text_start(&start, &size, name) < 0) 164062306a36Sopenharmony_ci return -1; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci map = machine__addnew_module_map(machine, start, name); 164362306a36Sopenharmony_ci if (map == NULL) 164462306a36Sopenharmony_ci return -1; 164562306a36Sopenharmony_ci map__set_end(map, start + size); 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci dso__kernel_module_get_build_id(map__dso(map), machine->root_dir); 164862306a36Sopenharmony_ci map__put(map); 164962306a36Sopenharmony_ci return 0; 165062306a36Sopenharmony_ci} 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_cistatic int machine__create_modules(struct machine *machine) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci const char *modules; 165562306a36Sopenharmony_ci char path[PATH_MAX]; 165662306a36Sopenharmony_ci 165762306a36Sopenharmony_ci if (machine__is_default_guest(machine)) { 165862306a36Sopenharmony_ci modules = symbol_conf.default_guest_modules; 165962306a36Sopenharmony_ci } else { 166062306a36Sopenharmony_ci snprintf(path, PATH_MAX, "%s/proc/modules", machine->root_dir); 166162306a36Sopenharmony_ci modules = path; 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci if (symbol__restricted_filename(modules, "/proc/modules")) 166562306a36Sopenharmony_ci return -1; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci if (modules__parse(modules, machine, machine__create_module)) 166862306a36Sopenharmony_ci return -1; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci if (!machine__set_modules_path(machine)) 167162306a36Sopenharmony_ci return 0; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci pr_debug("Problems setting modules path maps, continuing anyway...\n"); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci return 0; 167662306a36Sopenharmony_ci} 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_cistatic void machine__set_kernel_mmap(struct machine *machine, 167962306a36Sopenharmony_ci u64 start, u64 end) 168062306a36Sopenharmony_ci{ 168162306a36Sopenharmony_ci map__set_start(machine->vmlinux_map, start); 168262306a36Sopenharmony_ci map__set_end(machine->vmlinux_map, end); 168362306a36Sopenharmony_ci /* 168462306a36Sopenharmony_ci * Be a bit paranoid here, some perf.data file came with 168562306a36Sopenharmony_ci * a zero sized synthesized MMAP event for the kernel. 168662306a36Sopenharmony_ci */ 168762306a36Sopenharmony_ci if (start == 0 && end == 0) 168862306a36Sopenharmony_ci map__set_end(machine->vmlinux_map, ~0ULL); 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cistatic int machine__update_kernel_mmap(struct machine *machine, 169262306a36Sopenharmony_ci u64 start, u64 end) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci struct map *orig, *updated; 169562306a36Sopenharmony_ci int err; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci orig = machine->vmlinux_map; 169862306a36Sopenharmony_ci updated = map__get(orig); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci machine->vmlinux_map = updated; 170162306a36Sopenharmony_ci machine__set_kernel_mmap(machine, start, end); 170262306a36Sopenharmony_ci maps__remove(machine__kernel_maps(machine), orig); 170362306a36Sopenharmony_ci err = maps__insert(machine__kernel_maps(machine), updated); 170462306a36Sopenharmony_ci map__put(orig); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci return err; 170762306a36Sopenharmony_ci} 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ciint machine__create_kernel_maps(struct machine *machine) 171062306a36Sopenharmony_ci{ 171162306a36Sopenharmony_ci struct dso *kernel = machine__get_kernel(machine); 171262306a36Sopenharmony_ci const char *name = NULL; 171362306a36Sopenharmony_ci u64 start = 0, end = ~0ULL; 171462306a36Sopenharmony_ci int ret; 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci if (kernel == NULL) 171762306a36Sopenharmony_ci return -1; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci ret = __machine__create_kernel_maps(machine, kernel); 172062306a36Sopenharmony_ci if (ret < 0) 172162306a36Sopenharmony_ci goto out_put; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { 172462306a36Sopenharmony_ci if (machine__is_host(machine)) 172562306a36Sopenharmony_ci pr_debug("Problems creating module maps, " 172662306a36Sopenharmony_ci "continuing anyway...\n"); 172762306a36Sopenharmony_ci else 172862306a36Sopenharmony_ci pr_debug("Problems creating module maps for guest %d, " 172962306a36Sopenharmony_ci "continuing anyway...\n", machine->pid); 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci if (!machine__get_running_kernel_start(machine, &name, &start, &end)) { 173362306a36Sopenharmony_ci if (name && 173462306a36Sopenharmony_ci map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map, name, start)) { 173562306a36Sopenharmony_ci machine__destroy_kernel_maps(machine); 173662306a36Sopenharmony_ci ret = -1; 173762306a36Sopenharmony_ci goto out_put; 173862306a36Sopenharmony_ci } 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci /* 174162306a36Sopenharmony_ci * we have a real start address now, so re-order the kmaps 174262306a36Sopenharmony_ci * assume it's the last in the kmaps 174362306a36Sopenharmony_ci */ 174462306a36Sopenharmony_ci ret = machine__update_kernel_mmap(machine, start, end); 174562306a36Sopenharmony_ci if (ret < 0) 174662306a36Sopenharmony_ci goto out_put; 174762306a36Sopenharmony_ci } 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci if (machine__create_extra_kernel_maps(machine, kernel)) 175062306a36Sopenharmony_ci pr_debug("Problems creating extra kernel maps, continuing anyway...\n"); 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci if (end == ~0ULL) { 175362306a36Sopenharmony_ci /* update end address of the kernel map using adjacent module address */ 175462306a36Sopenharmony_ci struct map_rb_node *rb_node = maps__find_node(machine__kernel_maps(machine), 175562306a36Sopenharmony_ci machine__kernel_map(machine)); 175662306a36Sopenharmony_ci struct map_rb_node *next = map_rb_node__next(rb_node); 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci if (next) 175962306a36Sopenharmony_ci machine__set_kernel_mmap(machine, start, map__start(next->map)); 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ciout_put: 176362306a36Sopenharmony_ci dso__put(kernel); 176462306a36Sopenharmony_ci return ret; 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_cistatic bool machine__uses_kcore(struct machine *machine) 176862306a36Sopenharmony_ci{ 176962306a36Sopenharmony_ci struct dso *dso; 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci list_for_each_entry(dso, &machine->dsos.head, node) { 177262306a36Sopenharmony_ci if (dso__is_kcore(dso)) 177362306a36Sopenharmony_ci return true; 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci return false; 177762306a36Sopenharmony_ci} 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_cistatic bool perf_event__is_extra_kernel_mmap(struct machine *machine, 178062306a36Sopenharmony_ci struct extra_kernel_map *xm) 178162306a36Sopenharmony_ci{ 178262306a36Sopenharmony_ci return machine__is(machine, "x86_64") && 178362306a36Sopenharmony_ci is_entry_trampoline(xm->name); 178462306a36Sopenharmony_ci} 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_cistatic int machine__process_extra_kernel_map(struct machine *machine, 178762306a36Sopenharmony_ci struct extra_kernel_map *xm) 178862306a36Sopenharmony_ci{ 178962306a36Sopenharmony_ci struct dso *kernel = machine__kernel_dso(machine); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (kernel == NULL) 179262306a36Sopenharmony_ci return -1; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci return machine__create_extra_kernel_map(machine, kernel, xm); 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_cistatic int machine__process_kernel_mmap_event(struct machine *machine, 179862306a36Sopenharmony_ci struct extra_kernel_map *xm, 179962306a36Sopenharmony_ci struct build_id *bid) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci enum dso_space_type dso_space; 180262306a36Sopenharmony_ci bool is_kernel_mmap; 180362306a36Sopenharmony_ci const char *mmap_name = machine->mmap_name; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci /* If we have maps from kcore then we do not need or want any others */ 180662306a36Sopenharmony_ci if (machine__uses_kcore(machine)) 180762306a36Sopenharmony_ci return 0; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci if (machine__is_host(machine)) 181062306a36Sopenharmony_ci dso_space = DSO_SPACE__KERNEL; 181162306a36Sopenharmony_ci else 181262306a36Sopenharmony_ci dso_space = DSO_SPACE__KERNEL_GUEST; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci is_kernel_mmap = memcmp(xm->name, mmap_name, strlen(mmap_name) - 1) == 0; 181562306a36Sopenharmony_ci if (!is_kernel_mmap && !machine__is_host(machine)) { 181662306a36Sopenharmony_ci /* 181762306a36Sopenharmony_ci * If the event was recorded inside the guest and injected into 181862306a36Sopenharmony_ci * the host perf.data file, then it will match a host mmap_name, 181962306a36Sopenharmony_ci * so try that - see machine__set_mmap_name(). 182062306a36Sopenharmony_ci */ 182162306a36Sopenharmony_ci mmap_name = "[kernel.kallsyms]"; 182262306a36Sopenharmony_ci is_kernel_mmap = memcmp(xm->name, mmap_name, strlen(mmap_name) - 1) == 0; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci if (xm->name[0] == '/' || 182562306a36Sopenharmony_ci (!is_kernel_mmap && xm->name[0] == '[')) { 182662306a36Sopenharmony_ci struct map *map = machine__addnew_module_map(machine, xm->start, xm->name); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (map == NULL) 182962306a36Sopenharmony_ci goto out_problem; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci map__set_end(map, map__start(map) + xm->end - xm->start); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci if (build_id__is_defined(bid)) 183462306a36Sopenharmony_ci dso__set_build_id(map__dso(map), bid); 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci map__put(map); 183762306a36Sopenharmony_ci } else if (is_kernel_mmap) { 183862306a36Sopenharmony_ci const char *symbol_name = xm->name + strlen(mmap_name); 183962306a36Sopenharmony_ci /* 184062306a36Sopenharmony_ci * Should be there already, from the build-id table in 184162306a36Sopenharmony_ci * the header. 184262306a36Sopenharmony_ci */ 184362306a36Sopenharmony_ci struct dso *kernel = NULL; 184462306a36Sopenharmony_ci struct dso *dso; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci down_read(&machine->dsos.lock); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci list_for_each_entry(dso, &machine->dsos.head, node) { 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci /* 185162306a36Sopenharmony_ci * The cpumode passed to is_kernel_module is not the 185262306a36Sopenharmony_ci * cpumode of *this* event. If we insist on passing 185362306a36Sopenharmony_ci * correct cpumode to is_kernel_module, we should 185462306a36Sopenharmony_ci * record the cpumode when we adding this dso to the 185562306a36Sopenharmony_ci * linked list. 185662306a36Sopenharmony_ci * 185762306a36Sopenharmony_ci * However we don't really need passing correct 185862306a36Sopenharmony_ci * cpumode. We know the correct cpumode must be kernel 185962306a36Sopenharmony_ci * mode (if not, we should not link it onto kernel_dsos 186062306a36Sopenharmony_ci * list). 186162306a36Sopenharmony_ci * 186262306a36Sopenharmony_ci * Therefore, we pass PERF_RECORD_MISC_CPUMODE_UNKNOWN. 186362306a36Sopenharmony_ci * is_kernel_module() treats it as a kernel cpumode. 186462306a36Sopenharmony_ci */ 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci if (!dso->kernel || 186762306a36Sopenharmony_ci is_kernel_module(dso->long_name, 186862306a36Sopenharmony_ci PERF_RECORD_MISC_CPUMODE_UNKNOWN)) 186962306a36Sopenharmony_ci continue; 187062306a36Sopenharmony_ci 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_ci kernel = dso__get(dso); 187362306a36Sopenharmony_ci break; 187462306a36Sopenharmony_ci } 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci up_read(&machine->dsos.lock); 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci if (kernel == NULL) 187962306a36Sopenharmony_ci kernel = machine__findnew_dso(machine, machine->mmap_name); 188062306a36Sopenharmony_ci if (kernel == NULL) 188162306a36Sopenharmony_ci goto out_problem; 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci kernel->kernel = dso_space; 188462306a36Sopenharmony_ci if (__machine__create_kernel_maps(machine, kernel) < 0) { 188562306a36Sopenharmony_ci dso__put(kernel); 188662306a36Sopenharmony_ci goto out_problem; 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci if (strstr(kernel->long_name, "vmlinux")) 189062306a36Sopenharmony_ci dso__set_short_name(kernel, "[kernel.vmlinux]", false); 189162306a36Sopenharmony_ci 189262306a36Sopenharmony_ci if (machine__update_kernel_mmap(machine, xm->start, xm->end) < 0) { 189362306a36Sopenharmony_ci dso__put(kernel); 189462306a36Sopenharmony_ci goto out_problem; 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci if (build_id__is_defined(bid)) 189862306a36Sopenharmony_ci dso__set_build_id(kernel, bid); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci /* 190162306a36Sopenharmony_ci * Avoid using a zero address (kptr_restrict) for the ref reloc 190262306a36Sopenharmony_ci * symbol. Effectively having zero here means that at record 190362306a36Sopenharmony_ci * time /proc/sys/kernel/kptr_restrict was non zero. 190462306a36Sopenharmony_ci */ 190562306a36Sopenharmony_ci if (xm->pgoff != 0) { 190662306a36Sopenharmony_ci map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map, 190762306a36Sopenharmony_ci symbol_name, 190862306a36Sopenharmony_ci xm->pgoff); 190962306a36Sopenharmony_ci } 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci if (machine__is_default_guest(machine)) { 191262306a36Sopenharmony_ci /* 191362306a36Sopenharmony_ci * preload dso of guest kernel and modules 191462306a36Sopenharmony_ci */ 191562306a36Sopenharmony_ci dso__load(kernel, machine__kernel_map(machine)); 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci dso__put(kernel); 191862306a36Sopenharmony_ci } else if (perf_event__is_extra_kernel_mmap(machine, xm)) { 191962306a36Sopenharmony_ci return machine__process_extra_kernel_map(machine, xm); 192062306a36Sopenharmony_ci } 192162306a36Sopenharmony_ci return 0; 192262306a36Sopenharmony_ciout_problem: 192362306a36Sopenharmony_ci return -1; 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ciint machine__process_mmap2_event(struct machine *machine, 192762306a36Sopenharmony_ci union perf_event *event, 192862306a36Sopenharmony_ci struct perf_sample *sample) 192962306a36Sopenharmony_ci{ 193062306a36Sopenharmony_ci struct thread *thread; 193162306a36Sopenharmony_ci struct map *map; 193262306a36Sopenharmony_ci struct dso_id dso_id = { 193362306a36Sopenharmony_ci .maj = event->mmap2.maj, 193462306a36Sopenharmony_ci .min = event->mmap2.min, 193562306a36Sopenharmony_ci .ino = event->mmap2.ino, 193662306a36Sopenharmony_ci .ino_generation = event->mmap2.ino_generation, 193762306a36Sopenharmony_ci }; 193862306a36Sopenharmony_ci struct build_id __bid, *bid = NULL; 193962306a36Sopenharmony_ci int ret = 0; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci if (dump_trace) 194262306a36Sopenharmony_ci perf_event__fprintf_mmap2(event, stdout); 194362306a36Sopenharmony_ci 194462306a36Sopenharmony_ci if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) { 194562306a36Sopenharmony_ci bid = &__bid; 194662306a36Sopenharmony_ci build_id__init(bid, event->mmap2.build_id, event->mmap2.build_id_size); 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 195062306a36Sopenharmony_ci sample->cpumode == PERF_RECORD_MISC_KERNEL) { 195162306a36Sopenharmony_ci struct extra_kernel_map xm = { 195262306a36Sopenharmony_ci .start = event->mmap2.start, 195362306a36Sopenharmony_ci .end = event->mmap2.start + event->mmap2.len, 195462306a36Sopenharmony_ci .pgoff = event->mmap2.pgoff, 195562306a36Sopenharmony_ci }; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci strlcpy(xm.name, event->mmap2.filename, KMAP_NAME_LEN); 195862306a36Sopenharmony_ci ret = machine__process_kernel_mmap_event(machine, &xm, bid); 195962306a36Sopenharmony_ci if (ret < 0) 196062306a36Sopenharmony_ci goto out_problem; 196162306a36Sopenharmony_ci return 0; 196262306a36Sopenharmony_ci } 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci thread = machine__findnew_thread(machine, event->mmap2.pid, 196562306a36Sopenharmony_ci event->mmap2.tid); 196662306a36Sopenharmony_ci if (thread == NULL) 196762306a36Sopenharmony_ci goto out_problem; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci map = map__new(machine, event->mmap2.start, 197062306a36Sopenharmony_ci event->mmap2.len, event->mmap2.pgoff, 197162306a36Sopenharmony_ci &dso_id, event->mmap2.prot, 197262306a36Sopenharmony_ci event->mmap2.flags, bid, 197362306a36Sopenharmony_ci event->mmap2.filename, thread); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci if (map == NULL) 197662306a36Sopenharmony_ci goto out_problem_map; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci ret = thread__insert_map(thread, map); 197962306a36Sopenharmony_ci if (ret) 198062306a36Sopenharmony_ci goto out_problem_insert; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci thread__put(thread); 198362306a36Sopenharmony_ci map__put(map); 198462306a36Sopenharmony_ci return 0; 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ciout_problem_insert: 198762306a36Sopenharmony_ci map__put(map); 198862306a36Sopenharmony_ciout_problem_map: 198962306a36Sopenharmony_ci thread__put(thread); 199062306a36Sopenharmony_ciout_problem: 199162306a36Sopenharmony_ci dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n"); 199262306a36Sopenharmony_ci return 0; 199362306a36Sopenharmony_ci} 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ciint machine__process_mmap_event(struct machine *machine, union perf_event *event, 199662306a36Sopenharmony_ci struct perf_sample *sample) 199762306a36Sopenharmony_ci{ 199862306a36Sopenharmony_ci struct thread *thread; 199962306a36Sopenharmony_ci struct map *map; 200062306a36Sopenharmony_ci u32 prot = 0; 200162306a36Sopenharmony_ci int ret = 0; 200262306a36Sopenharmony_ci 200362306a36Sopenharmony_ci if (dump_trace) 200462306a36Sopenharmony_ci perf_event__fprintf_mmap(event, stdout); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci if (sample->cpumode == PERF_RECORD_MISC_GUEST_KERNEL || 200762306a36Sopenharmony_ci sample->cpumode == PERF_RECORD_MISC_KERNEL) { 200862306a36Sopenharmony_ci struct extra_kernel_map xm = { 200962306a36Sopenharmony_ci .start = event->mmap.start, 201062306a36Sopenharmony_ci .end = event->mmap.start + event->mmap.len, 201162306a36Sopenharmony_ci .pgoff = event->mmap.pgoff, 201262306a36Sopenharmony_ci }; 201362306a36Sopenharmony_ci 201462306a36Sopenharmony_ci strlcpy(xm.name, event->mmap.filename, KMAP_NAME_LEN); 201562306a36Sopenharmony_ci ret = machine__process_kernel_mmap_event(machine, &xm, NULL); 201662306a36Sopenharmony_ci if (ret < 0) 201762306a36Sopenharmony_ci goto out_problem; 201862306a36Sopenharmony_ci return 0; 201962306a36Sopenharmony_ci } 202062306a36Sopenharmony_ci 202162306a36Sopenharmony_ci thread = machine__findnew_thread(machine, event->mmap.pid, 202262306a36Sopenharmony_ci event->mmap.tid); 202362306a36Sopenharmony_ci if (thread == NULL) 202462306a36Sopenharmony_ci goto out_problem; 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci if (!(event->header.misc & PERF_RECORD_MISC_MMAP_DATA)) 202762306a36Sopenharmony_ci prot = PROT_EXEC; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci map = map__new(machine, event->mmap.start, 203062306a36Sopenharmony_ci event->mmap.len, event->mmap.pgoff, 203162306a36Sopenharmony_ci NULL, prot, 0, NULL, event->mmap.filename, thread); 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci if (map == NULL) 203462306a36Sopenharmony_ci goto out_problem_map; 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci ret = thread__insert_map(thread, map); 203762306a36Sopenharmony_ci if (ret) 203862306a36Sopenharmony_ci goto out_problem_insert; 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci thread__put(thread); 204162306a36Sopenharmony_ci map__put(map); 204262306a36Sopenharmony_ci return 0; 204362306a36Sopenharmony_ci 204462306a36Sopenharmony_ciout_problem_insert: 204562306a36Sopenharmony_ci map__put(map); 204662306a36Sopenharmony_ciout_problem_map: 204762306a36Sopenharmony_ci thread__put(thread); 204862306a36Sopenharmony_ciout_problem: 204962306a36Sopenharmony_ci dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); 205062306a36Sopenharmony_ci return 0; 205162306a36Sopenharmony_ci} 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_cistatic void __machine__remove_thread(struct machine *machine, struct thread_rb_node *nd, 205462306a36Sopenharmony_ci struct thread *th, bool lock) 205562306a36Sopenharmony_ci{ 205662306a36Sopenharmony_ci struct threads *threads = machine__threads(machine, thread__tid(th)); 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ci if (!nd) 205962306a36Sopenharmony_ci nd = thread_rb_node__find(th, &threads->entries.rb_root); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci if (threads->last_match && RC_CHK_ACCESS(threads->last_match) == RC_CHK_ACCESS(th)) 206262306a36Sopenharmony_ci threads__set_last_match(threads, NULL); 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ci if (lock) 206562306a36Sopenharmony_ci down_write(&threads->lock); 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ci BUG_ON(refcount_read(thread__refcnt(th)) == 0); 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci thread__put(nd->thread); 207062306a36Sopenharmony_ci rb_erase_cached(&nd->rb_node, &threads->entries); 207162306a36Sopenharmony_ci RB_CLEAR_NODE(&nd->rb_node); 207262306a36Sopenharmony_ci --threads->nr; 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci free(nd); 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci if (lock) 207762306a36Sopenharmony_ci up_write(&threads->lock); 207862306a36Sopenharmony_ci} 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_civoid machine__remove_thread(struct machine *machine, struct thread *th) 208162306a36Sopenharmony_ci{ 208262306a36Sopenharmony_ci return __machine__remove_thread(machine, NULL, th, true); 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ciint machine__process_fork_event(struct machine *machine, union perf_event *event, 208662306a36Sopenharmony_ci struct perf_sample *sample) 208762306a36Sopenharmony_ci{ 208862306a36Sopenharmony_ci struct thread *thread = machine__find_thread(machine, 208962306a36Sopenharmony_ci event->fork.pid, 209062306a36Sopenharmony_ci event->fork.tid); 209162306a36Sopenharmony_ci struct thread *parent = machine__findnew_thread(machine, 209262306a36Sopenharmony_ci event->fork.ppid, 209362306a36Sopenharmony_ci event->fork.ptid); 209462306a36Sopenharmony_ci bool do_maps_clone = true; 209562306a36Sopenharmony_ci int err = 0; 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci if (dump_trace) 209862306a36Sopenharmony_ci perf_event__fprintf_task(event, stdout); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci /* 210162306a36Sopenharmony_ci * There may be an existing thread that is not actually the parent, 210262306a36Sopenharmony_ci * either because we are processing events out of order, or because the 210362306a36Sopenharmony_ci * (fork) event that would have removed the thread was lost. Assume the 210462306a36Sopenharmony_ci * latter case and continue on as best we can. 210562306a36Sopenharmony_ci */ 210662306a36Sopenharmony_ci if (thread__pid(parent) != (pid_t)event->fork.ppid) { 210762306a36Sopenharmony_ci dump_printf("removing erroneous parent thread %d/%d\n", 210862306a36Sopenharmony_ci thread__pid(parent), thread__tid(parent)); 210962306a36Sopenharmony_ci machine__remove_thread(machine, parent); 211062306a36Sopenharmony_ci thread__put(parent); 211162306a36Sopenharmony_ci parent = machine__findnew_thread(machine, event->fork.ppid, 211262306a36Sopenharmony_ci event->fork.ptid); 211362306a36Sopenharmony_ci } 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci /* if a thread currently exists for the thread id remove it */ 211662306a36Sopenharmony_ci if (thread != NULL) { 211762306a36Sopenharmony_ci machine__remove_thread(machine, thread); 211862306a36Sopenharmony_ci thread__put(thread); 211962306a36Sopenharmony_ci } 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci thread = machine__findnew_thread(machine, event->fork.pid, 212262306a36Sopenharmony_ci event->fork.tid); 212362306a36Sopenharmony_ci /* 212462306a36Sopenharmony_ci * When synthesizing FORK events, we are trying to create thread 212562306a36Sopenharmony_ci * objects for the already running tasks on the machine. 212662306a36Sopenharmony_ci * 212762306a36Sopenharmony_ci * Normally, for a kernel FORK event, we want to clone the parent's 212862306a36Sopenharmony_ci * maps because that is what the kernel just did. 212962306a36Sopenharmony_ci * 213062306a36Sopenharmony_ci * But when synthesizing, this should not be done. If we do, we end up 213162306a36Sopenharmony_ci * with overlapping maps as we process the synthesized MMAP2 events that 213262306a36Sopenharmony_ci * get delivered shortly thereafter. 213362306a36Sopenharmony_ci * 213462306a36Sopenharmony_ci * Use the FORK event misc flags in an internal way to signal this 213562306a36Sopenharmony_ci * situation, so we can elide the map clone when appropriate. 213662306a36Sopenharmony_ci */ 213762306a36Sopenharmony_ci if (event->fork.header.misc & PERF_RECORD_MISC_FORK_EXEC) 213862306a36Sopenharmony_ci do_maps_clone = false; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci if (thread == NULL || parent == NULL || 214162306a36Sopenharmony_ci thread__fork(thread, parent, sample->time, do_maps_clone) < 0) { 214262306a36Sopenharmony_ci dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n"); 214362306a36Sopenharmony_ci err = -1; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci thread__put(thread); 214662306a36Sopenharmony_ci thread__put(parent); 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci return err; 214962306a36Sopenharmony_ci} 215062306a36Sopenharmony_ci 215162306a36Sopenharmony_ciint machine__process_exit_event(struct machine *machine, union perf_event *event, 215262306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci struct thread *thread = machine__find_thread(machine, 215562306a36Sopenharmony_ci event->fork.pid, 215662306a36Sopenharmony_ci event->fork.tid); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci if (dump_trace) 215962306a36Sopenharmony_ci perf_event__fprintf_task(event, stdout); 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci if (thread != NULL) 216262306a36Sopenharmony_ci thread__put(thread); 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci return 0; 216562306a36Sopenharmony_ci} 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ciint machine__process_event(struct machine *machine, union perf_event *event, 216862306a36Sopenharmony_ci struct perf_sample *sample) 216962306a36Sopenharmony_ci{ 217062306a36Sopenharmony_ci int ret; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci switch (event->header.type) { 217362306a36Sopenharmony_ci case PERF_RECORD_COMM: 217462306a36Sopenharmony_ci ret = machine__process_comm_event(machine, event, sample); break; 217562306a36Sopenharmony_ci case PERF_RECORD_MMAP: 217662306a36Sopenharmony_ci ret = machine__process_mmap_event(machine, event, sample); break; 217762306a36Sopenharmony_ci case PERF_RECORD_NAMESPACES: 217862306a36Sopenharmony_ci ret = machine__process_namespaces_event(machine, event, sample); break; 217962306a36Sopenharmony_ci case PERF_RECORD_CGROUP: 218062306a36Sopenharmony_ci ret = machine__process_cgroup_event(machine, event, sample); break; 218162306a36Sopenharmony_ci case PERF_RECORD_MMAP2: 218262306a36Sopenharmony_ci ret = machine__process_mmap2_event(machine, event, sample); break; 218362306a36Sopenharmony_ci case PERF_RECORD_FORK: 218462306a36Sopenharmony_ci ret = machine__process_fork_event(machine, event, sample); break; 218562306a36Sopenharmony_ci case PERF_RECORD_EXIT: 218662306a36Sopenharmony_ci ret = machine__process_exit_event(machine, event, sample); break; 218762306a36Sopenharmony_ci case PERF_RECORD_LOST: 218862306a36Sopenharmony_ci ret = machine__process_lost_event(machine, event, sample); break; 218962306a36Sopenharmony_ci case PERF_RECORD_AUX: 219062306a36Sopenharmony_ci ret = machine__process_aux_event(machine, event); break; 219162306a36Sopenharmony_ci case PERF_RECORD_ITRACE_START: 219262306a36Sopenharmony_ci ret = machine__process_itrace_start_event(machine, event); break; 219362306a36Sopenharmony_ci case PERF_RECORD_LOST_SAMPLES: 219462306a36Sopenharmony_ci ret = machine__process_lost_samples_event(machine, event, sample); break; 219562306a36Sopenharmony_ci case PERF_RECORD_SWITCH: 219662306a36Sopenharmony_ci case PERF_RECORD_SWITCH_CPU_WIDE: 219762306a36Sopenharmony_ci ret = machine__process_switch_event(machine, event); break; 219862306a36Sopenharmony_ci case PERF_RECORD_KSYMBOL: 219962306a36Sopenharmony_ci ret = machine__process_ksymbol(machine, event, sample); break; 220062306a36Sopenharmony_ci case PERF_RECORD_BPF_EVENT: 220162306a36Sopenharmony_ci ret = machine__process_bpf(machine, event, sample); break; 220262306a36Sopenharmony_ci case PERF_RECORD_TEXT_POKE: 220362306a36Sopenharmony_ci ret = machine__process_text_poke(machine, event, sample); break; 220462306a36Sopenharmony_ci case PERF_RECORD_AUX_OUTPUT_HW_ID: 220562306a36Sopenharmony_ci ret = machine__process_aux_output_hw_id_event(machine, event); break; 220662306a36Sopenharmony_ci default: 220762306a36Sopenharmony_ci ret = -1; 220862306a36Sopenharmony_ci break; 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci return ret; 221262306a36Sopenharmony_ci} 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_cistatic bool symbol__match_regex(struct symbol *sym, regex_t *regex) 221562306a36Sopenharmony_ci{ 221662306a36Sopenharmony_ci if (!regexec(regex, sym->name, 0, NULL, 0)) 221762306a36Sopenharmony_ci return true; 221862306a36Sopenharmony_ci return false; 221962306a36Sopenharmony_ci} 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_cistatic void ip__resolve_ams(struct thread *thread, 222262306a36Sopenharmony_ci struct addr_map_symbol *ams, 222362306a36Sopenharmony_ci u64 ip) 222462306a36Sopenharmony_ci{ 222562306a36Sopenharmony_ci struct addr_location al; 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_ci addr_location__init(&al); 222862306a36Sopenharmony_ci /* 222962306a36Sopenharmony_ci * We cannot use the header.misc hint to determine whether a 223062306a36Sopenharmony_ci * branch stack address is user, kernel, guest, hypervisor. 223162306a36Sopenharmony_ci * Branches may straddle the kernel/user/hypervisor boundaries. 223262306a36Sopenharmony_ci * Thus, we have to try consecutively until we find a match 223362306a36Sopenharmony_ci * or else, the symbol is unknown 223462306a36Sopenharmony_ci */ 223562306a36Sopenharmony_ci thread__find_cpumode_addr_location(thread, ip, &al); 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci ams->addr = ip; 223862306a36Sopenharmony_ci ams->al_addr = al.addr; 223962306a36Sopenharmony_ci ams->al_level = al.level; 224062306a36Sopenharmony_ci ams->ms.maps = maps__get(al.maps); 224162306a36Sopenharmony_ci ams->ms.sym = al.sym; 224262306a36Sopenharmony_ci ams->ms.map = map__get(al.map); 224362306a36Sopenharmony_ci ams->phys_addr = 0; 224462306a36Sopenharmony_ci ams->data_page_size = 0; 224562306a36Sopenharmony_ci addr_location__exit(&al); 224662306a36Sopenharmony_ci} 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_cistatic void ip__resolve_data(struct thread *thread, 224962306a36Sopenharmony_ci u8 m, struct addr_map_symbol *ams, 225062306a36Sopenharmony_ci u64 addr, u64 phys_addr, u64 daddr_page_size) 225162306a36Sopenharmony_ci{ 225262306a36Sopenharmony_ci struct addr_location al; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci addr_location__init(&al); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci thread__find_symbol(thread, m, addr, &al); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci ams->addr = addr; 225962306a36Sopenharmony_ci ams->al_addr = al.addr; 226062306a36Sopenharmony_ci ams->al_level = al.level; 226162306a36Sopenharmony_ci ams->ms.maps = maps__get(al.maps); 226262306a36Sopenharmony_ci ams->ms.sym = al.sym; 226362306a36Sopenharmony_ci ams->ms.map = map__get(al.map); 226462306a36Sopenharmony_ci ams->phys_addr = phys_addr; 226562306a36Sopenharmony_ci ams->data_page_size = daddr_page_size; 226662306a36Sopenharmony_ci addr_location__exit(&al); 226762306a36Sopenharmony_ci} 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_cistruct mem_info *sample__resolve_mem(struct perf_sample *sample, 227062306a36Sopenharmony_ci struct addr_location *al) 227162306a36Sopenharmony_ci{ 227262306a36Sopenharmony_ci struct mem_info *mi = mem_info__new(); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci if (!mi) 227562306a36Sopenharmony_ci return NULL; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci ip__resolve_ams(al->thread, &mi->iaddr, sample->ip); 227862306a36Sopenharmony_ci ip__resolve_data(al->thread, al->cpumode, &mi->daddr, 227962306a36Sopenharmony_ci sample->addr, sample->phys_addr, 228062306a36Sopenharmony_ci sample->data_page_size); 228162306a36Sopenharmony_ci mi->data_src.val = sample->data_src; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci return mi; 228462306a36Sopenharmony_ci} 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_cistatic char *callchain_srcline(struct map_symbol *ms, u64 ip) 228762306a36Sopenharmony_ci{ 228862306a36Sopenharmony_ci struct map *map = ms->map; 228962306a36Sopenharmony_ci char *srcline = NULL; 229062306a36Sopenharmony_ci struct dso *dso; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci if (!map || callchain_param.key == CCKEY_FUNCTION) 229362306a36Sopenharmony_ci return srcline; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci dso = map__dso(map); 229662306a36Sopenharmony_ci srcline = srcline__tree_find(&dso->srclines, ip); 229762306a36Sopenharmony_ci if (!srcline) { 229862306a36Sopenharmony_ci bool show_sym = false; 229962306a36Sopenharmony_ci bool show_addr = callchain_param.key == CCKEY_ADDRESS; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci srcline = get_srcline(dso, map__rip_2objdump(map, ip), 230262306a36Sopenharmony_ci ms->sym, show_sym, show_addr, ip); 230362306a36Sopenharmony_ci srcline__tree_insert(&dso->srclines, ip, srcline); 230462306a36Sopenharmony_ci } 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci return srcline; 230762306a36Sopenharmony_ci} 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_cistruct iterations { 231062306a36Sopenharmony_ci int nr_loop_iter; 231162306a36Sopenharmony_ci u64 cycles; 231262306a36Sopenharmony_ci}; 231362306a36Sopenharmony_ci 231462306a36Sopenharmony_cistatic int add_callchain_ip(struct thread *thread, 231562306a36Sopenharmony_ci struct callchain_cursor *cursor, 231662306a36Sopenharmony_ci struct symbol **parent, 231762306a36Sopenharmony_ci struct addr_location *root_al, 231862306a36Sopenharmony_ci u8 *cpumode, 231962306a36Sopenharmony_ci u64 ip, 232062306a36Sopenharmony_ci bool branch, 232162306a36Sopenharmony_ci struct branch_flags *flags, 232262306a36Sopenharmony_ci struct iterations *iter, 232362306a36Sopenharmony_ci u64 branch_from) 232462306a36Sopenharmony_ci{ 232562306a36Sopenharmony_ci struct map_symbol ms = {}; 232662306a36Sopenharmony_ci struct addr_location al; 232762306a36Sopenharmony_ci int nr_loop_iter = 0, err = 0; 232862306a36Sopenharmony_ci u64 iter_cycles = 0; 232962306a36Sopenharmony_ci const char *srcline = NULL; 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci addr_location__init(&al); 233262306a36Sopenharmony_ci al.filtered = 0; 233362306a36Sopenharmony_ci al.sym = NULL; 233462306a36Sopenharmony_ci al.srcline = NULL; 233562306a36Sopenharmony_ci if (!cpumode) { 233662306a36Sopenharmony_ci thread__find_cpumode_addr_location(thread, ip, &al); 233762306a36Sopenharmony_ci } else { 233862306a36Sopenharmony_ci if (ip >= PERF_CONTEXT_MAX) { 233962306a36Sopenharmony_ci switch (ip) { 234062306a36Sopenharmony_ci case PERF_CONTEXT_HV: 234162306a36Sopenharmony_ci *cpumode = PERF_RECORD_MISC_HYPERVISOR; 234262306a36Sopenharmony_ci break; 234362306a36Sopenharmony_ci case PERF_CONTEXT_KERNEL: 234462306a36Sopenharmony_ci *cpumode = PERF_RECORD_MISC_KERNEL; 234562306a36Sopenharmony_ci break; 234662306a36Sopenharmony_ci case PERF_CONTEXT_USER: 234762306a36Sopenharmony_ci *cpumode = PERF_RECORD_MISC_USER; 234862306a36Sopenharmony_ci break; 234962306a36Sopenharmony_ci default: 235062306a36Sopenharmony_ci pr_debug("invalid callchain context: " 235162306a36Sopenharmony_ci "%"PRId64"\n", (s64) ip); 235262306a36Sopenharmony_ci /* 235362306a36Sopenharmony_ci * It seems the callchain is corrupted. 235462306a36Sopenharmony_ci * Discard all. 235562306a36Sopenharmony_ci */ 235662306a36Sopenharmony_ci callchain_cursor_reset(cursor); 235762306a36Sopenharmony_ci err = 1; 235862306a36Sopenharmony_ci goto out; 235962306a36Sopenharmony_ci } 236062306a36Sopenharmony_ci goto out; 236162306a36Sopenharmony_ci } 236262306a36Sopenharmony_ci thread__find_symbol(thread, *cpumode, ip, &al); 236362306a36Sopenharmony_ci } 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci if (al.sym != NULL) { 236662306a36Sopenharmony_ci if (perf_hpp_list.parent && !*parent && 236762306a36Sopenharmony_ci symbol__match_regex(al.sym, &parent_regex)) 236862306a36Sopenharmony_ci *parent = al.sym; 236962306a36Sopenharmony_ci else if (have_ignore_callees && root_al && 237062306a36Sopenharmony_ci symbol__match_regex(al.sym, &ignore_callees_regex)) { 237162306a36Sopenharmony_ci /* Treat this symbol as the root, 237262306a36Sopenharmony_ci forgetting its callees. */ 237362306a36Sopenharmony_ci addr_location__copy(root_al, &al); 237462306a36Sopenharmony_ci callchain_cursor_reset(cursor); 237562306a36Sopenharmony_ci } 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci if (symbol_conf.hide_unresolved && al.sym == NULL) 237962306a36Sopenharmony_ci goto out; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci if (iter) { 238262306a36Sopenharmony_ci nr_loop_iter = iter->nr_loop_iter; 238362306a36Sopenharmony_ci iter_cycles = iter->cycles; 238462306a36Sopenharmony_ci } 238562306a36Sopenharmony_ci 238662306a36Sopenharmony_ci ms.maps = maps__get(al.maps); 238762306a36Sopenharmony_ci ms.map = map__get(al.map); 238862306a36Sopenharmony_ci ms.sym = al.sym; 238962306a36Sopenharmony_ci srcline = callchain_srcline(&ms, al.addr); 239062306a36Sopenharmony_ci err = callchain_cursor_append(cursor, ip, &ms, 239162306a36Sopenharmony_ci branch, flags, nr_loop_iter, 239262306a36Sopenharmony_ci iter_cycles, branch_from, srcline); 239362306a36Sopenharmony_ciout: 239462306a36Sopenharmony_ci addr_location__exit(&al); 239562306a36Sopenharmony_ci maps__put(ms.maps); 239662306a36Sopenharmony_ci map__put(ms.map); 239762306a36Sopenharmony_ci return err; 239862306a36Sopenharmony_ci} 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_cistruct branch_info *sample__resolve_bstack(struct perf_sample *sample, 240162306a36Sopenharmony_ci struct addr_location *al) 240262306a36Sopenharmony_ci{ 240362306a36Sopenharmony_ci unsigned int i; 240462306a36Sopenharmony_ci const struct branch_stack *bs = sample->branch_stack; 240562306a36Sopenharmony_ci struct branch_entry *entries = perf_sample__branch_entries(sample); 240662306a36Sopenharmony_ci struct branch_info *bi = calloc(bs->nr, sizeof(struct branch_info)); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci if (!bi) 240962306a36Sopenharmony_ci return NULL; 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci for (i = 0; i < bs->nr; i++) { 241262306a36Sopenharmony_ci ip__resolve_ams(al->thread, &bi[i].to, entries[i].to); 241362306a36Sopenharmony_ci ip__resolve_ams(al->thread, &bi[i].from, entries[i].from); 241462306a36Sopenharmony_ci bi[i].flags = entries[i].flags; 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci return bi; 241762306a36Sopenharmony_ci} 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_cistatic void save_iterations(struct iterations *iter, 242062306a36Sopenharmony_ci struct branch_entry *be, int nr) 242162306a36Sopenharmony_ci{ 242262306a36Sopenharmony_ci int i; 242362306a36Sopenharmony_ci 242462306a36Sopenharmony_ci iter->nr_loop_iter++; 242562306a36Sopenharmony_ci iter->cycles = 0; 242662306a36Sopenharmony_ci 242762306a36Sopenharmony_ci for (i = 0; i < nr; i++) 242862306a36Sopenharmony_ci iter->cycles += be[i].flags.cycles; 242962306a36Sopenharmony_ci} 243062306a36Sopenharmony_ci 243162306a36Sopenharmony_ci#define CHASHSZ 127 243262306a36Sopenharmony_ci#define CHASHBITS 7 243362306a36Sopenharmony_ci#define NO_ENTRY 0xff 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_ci#define PERF_MAX_BRANCH_DEPTH 127 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci/* Remove loops. */ 243862306a36Sopenharmony_cistatic int remove_loops(struct branch_entry *l, int nr, 243962306a36Sopenharmony_ci struct iterations *iter) 244062306a36Sopenharmony_ci{ 244162306a36Sopenharmony_ci int i, j, off; 244262306a36Sopenharmony_ci unsigned char chash[CHASHSZ]; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci memset(chash, NO_ENTRY, sizeof(chash)); 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci BUG_ON(PERF_MAX_BRANCH_DEPTH > 255); 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 244962306a36Sopenharmony_ci int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci /* no collision handling for now */ 245262306a36Sopenharmony_ci if (chash[h] == NO_ENTRY) { 245362306a36Sopenharmony_ci chash[h] = i; 245462306a36Sopenharmony_ci } else if (l[chash[h]].from == l[i].from) { 245562306a36Sopenharmony_ci bool is_loop = true; 245662306a36Sopenharmony_ci /* check if it is a real loop */ 245762306a36Sopenharmony_ci off = 0; 245862306a36Sopenharmony_ci for (j = chash[h]; j < i && i + off < nr; j++, off++) 245962306a36Sopenharmony_ci if (l[j].from != l[i + off].from) { 246062306a36Sopenharmony_ci is_loop = false; 246162306a36Sopenharmony_ci break; 246262306a36Sopenharmony_ci } 246362306a36Sopenharmony_ci if (is_loop) { 246462306a36Sopenharmony_ci j = nr - (i + off); 246562306a36Sopenharmony_ci if (j > 0) { 246662306a36Sopenharmony_ci save_iterations(iter + i + off, 246762306a36Sopenharmony_ci l + i, off); 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci memmove(iter + i, iter + i + off, 247062306a36Sopenharmony_ci j * sizeof(*iter)); 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ci memmove(l + i, l + i + off, 247362306a36Sopenharmony_ci j * sizeof(*l)); 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci nr -= off; 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci } 247962306a36Sopenharmony_ci } 248062306a36Sopenharmony_ci return nr; 248162306a36Sopenharmony_ci} 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_cistatic int lbr_callchain_add_kernel_ip(struct thread *thread, 248462306a36Sopenharmony_ci struct callchain_cursor *cursor, 248562306a36Sopenharmony_ci struct perf_sample *sample, 248662306a36Sopenharmony_ci struct symbol **parent, 248762306a36Sopenharmony_ci struct addr_location *root_al, 248862306a36Sopenharmony_ci u64 branch_from, 248962306a36Sopenharmony_ci bool callee, int end) 249062306a36Sopenharmony_ci{ 249162306a36Sopenharmony_ci struct ip_callchain *chain = sample->callchain; 249262306a36Sopenharmony_ci u8 cpumode = PERF_RECORD_MISC_USER; 249362306a36Sopenharmony_ci int err, i; 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci if (callee) { 249662306a36Sopenharmony_ci for (i = 0; i < end + 1; i++) { 249762306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 249862306a36Sopenharmony_ci root_al, &cpumode, chain->ips[i], 249962306a36Sopenharmony_ci false, NULL, NULL, branch_from); 250062306a36Sopenharmony_ci if (err) 250162306a36Sopenharmony_ci return err; 250262306a36Sopenharmony_ci } 250362306a36Sopenharmony_ci return 0; 250462306a36Sopenharmony_ci } 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci for (i = end; i >= 0; i--) { 250762306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 250862306a36Sopenharmony_ci root_al, &cpumode, chain->ips[i], 250962306a36Sopenharmony_ci false, NULL, NULL, branch_from); 251062306a36Sopenharmony_ci if (err) 251162306a36Sopenharmony_ci return err; 251262306a36Sopenharmony_ci } 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci return 0; 251562306a36Sopenharmony_ci} 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_cistatic void save_lbr_cursor_node(struct thread *thread, 251862306a36Sopenharmony_ci struct callchain_cursor *cursor, 251962306a36Sopenharmony_ci int idx) 252062306a36Sopenharmony_ci{ 252162306a36Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread); 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci if (!lbr_stitch) 252462306a36Sopenharmony_ci return; 252562306a36Sopenharmony_ci 252662306a36Sopenharmony_ci if (cursor->pos == cursor->nr) { 252762306a36Sopenharmony_ci lbr_stitch->prev_lbr_cursor[idx].valid = false; 252862306a36Sopenharmony_ci return; 252962306a36Sopenharmony_ci } 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci if (!cursor->curr) 253262306a36Sopenharmony_ci cursor->curr = cursor->first; 253362306a36Sopenharmony_ci else 253462306a36Sopenharmony_ci cursor->curr = cursor->curr->next; 253562306a36Sopenharmony_ci memcpy(&lbr_stitch->prev_lbr_cursor[idx], cursor->curr, 253662306a36Sopenharmony_ci sizeof(struct callchain_cursor_node)); 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci lbr_stitch->prev_lbr_cursor[idx].valid = true; 253962306a36Sopenharmony_ci cursor->pos++; 254062306a36Sopenharmony_ci} 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_cistatic int lbr_callchain_add_lbr_ip(struct thread *thread, 254362306a36Sopenharmony_ci struct callchain_cursor *cursor, 254462306a36Sopenharmony_ci struct perf_sample *sample, 254562306a36Sopenharmony_ci struct symbol **parent, 254662306a36Sopenharmony_ci struct addr_location *root_al, 254762306a36Sopenharmony_ci u64 *branch_from, 254862306a36Sopenharmony_ci bool callee) 254962306a36Sopenharmony_ci{ 255062306a36Sopenharmony_ci struct branch_stack *lbr_stack = sample->branch_stack; 255162306a36Sopenharmony_ci struct branch_entry *entries = perf_sample__branch_entries(sample); 255262306a36Sopenharmony_ci u8 cpumode = PERF_RECORD_MISC_USER; 255362306a36Sopenharmony_ci int lbr_nr = lbr_stack->nr; 255462306a36Sopenharmony_ci struct branch_flags *flags; 255562306a36Sopenharmony_ci int err, i; 255662306a36Sopenharmony_ci u64 ip; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci /* 255962306a36Sopenharmony_ci * The curr and pos are not used in writing session. They are cleared 256062306a36Sopenharmony_ci * in callchain_cursor_commit() when the writing session is closed. 256162306a36Sopenharmony_ci * Using curr and pos to track the current cursor node. 256262306a36Sopenharmony_ci */ 256362306a36Sopenharmony_ci if (thread__lbr_stitch(thread)) { 256462306a36Sopenharmony_ci cursor->curr = NULL; 256562306a36Sopenharmony_ci cursor->pos = cursor->nr; 256662306a36Sopenharmony_ci if (cursor->nr) { 256762306a36Sopenharmony_ci cursor->curr = cursor->first; 256862306a36Sopenharmony_ci for (i = 0; i < (int)(cursor->nr - 1); i++) 256962306a36Sopenharmony_ci cursor->curr = cursor->curr->next; 257062306a36Sopenharmony_ci } 257162306a36Sopenharmony_ci } 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci if (callee) { 257462306a36Sopenharmony_ci /* Add LBR ip from first entries.to */ 257562306a36Sopenharmony_ci ip = entries[0].to; 257662306a36Sopenharmony_ci flags = &entries[0].flags; 257762306a36Sopenharmony_ci *branch_from = entries[0].from; 257862306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 257962306a36Sopenharmony_ci root_al, &cpumode, ip, 258062306a36Sopenharmony_ci true, flags, NULL, 258162306a36Sopenharmony_ci *branch_from); 258262306a36Sopenharmony_ci if (err) 258362306a36Sopenharmony_ci return err; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci /* 258662306a36Sopenharmony_ci * The number of cursor node increases. 258762306a36Sopenharmony_ci * Move the current cursor node. 258862306a36Sopenharmony_ci * But does not need to save current cursor node for entry 0. 258962306a36Sopenharmony_ci * It's impossible to stitch the whole LBRs of previous sample. 259062306a36Sopenharmony_ci */ 259162306a36Sopenharmony_ci if (thread__lbr_stitch(thread) && (cursor->pos != cursor->nr)) { 259262306a36Sopenharmony_ci if (!cursor->curr) 259362306a36Sopenharmony_ci cursor->curr = cursor->first; 259462306a36Sopenharmony_ci else 259562306a36Sopenharmony_ci cursor->curr = cursor->curr->next; 259662306a36Sopenharmony_ci cursor->pos++; 259762306a36Sopenharmony_ci } 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci /* Add LBR ip from entries.from one by one. */ 260062306a36Sopenharmony_ci for (i = 0; i < lbr_nr; i++) { 260162306a36Sopenharmony_ci ip = entries[i].from; 260262306a36Sopenharmony_ci flags = &entries[i].flags; 260362306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 260462306a36Sopenharmony_ci root_al, &cpumode, ip, 260562306a36Sopenharmony_ci true, flags, NULL, 260662306a36Sopenharmony_ci *branch_from); 260762306a36Sopenharmony_ci if (err) 260862306a36Sopenharmony_ci return err; 260962306a36Sopenharmony_ci save_lbr_cursor_node(thread, cursor, i); 261062306a36Sopenharmony_ci } 261162306a36Sopenharmony_ci return 0; 261262306a36Sopenharmony_ci } 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ci /* Add LBR ip from entries.from one by one. */ 261562306a36Sopenharmony_ci for (i = lbr_nr - 1; i >= 0; i--) { 261662306a36Sopenharmony_ci ip = entries[i].from; 261762306a36Sopenharmony_ci flags = &entries[i].flags; 261862306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 261962306a36Sopenharmony_ci root_al, &cpumode, ip, 262062306a36Sopenharmony_ci true, flags, NULL, 262162306a36Sopenharmony_ci *branch_from); 262262306a36Sopenharmony_ci if (err) 262362306a36Sopenharmony_ci return err; 262462306a36Sopenharmony_ci save_lbr_cursor_node(thread, cursor, i); 262562306a36Sopenharmony_ci } 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci if (lbr_nr > 0) { 262862306a36Sopenharmony_ci /* Add LBR ip from first entries.to */ 262962306a36Sopenharmony_ci ip = entries[0].to; 263062306a36Sopenharmony_ci flags = &entries[0].flags; 263162306a36Sopenharmony_ci *branch_from = entries[0].from; 263262306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 263362306a36Sopenharmony_ci root_al, &cpumode, ip, 263462306a36Sopenharmony_ci true, flags, NULL, 263562306a36Sopenharmony_ci *branch_from); 263662306a36Sopenharmony_ci if (err) 263762306a36Sopenharmony_ci return err; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci return 0; 264162306a36Sopenharmony_ci} 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_cistatic int lbr_callchain_add_stitched_lbr_ip(struct thread *thread, 264462306a36Sopenharmony_ci struct callchain_cursor *cursor) 264562306a36Sopenharmony_ci{ 264662306a36Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread); 264762306a36Sopenharmony_ci struct callchain_cursor_node *cnode; 264862306a36Sopenharmony_ci struct stitch_list *stitch_node; 264962306a36Sopenharmony_ci int err; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci list_for_each_entry(stitch_node, &lbr_stitch->lists, node) { 265262306a36Sopenharmony_ci cnode = &stitch_node->cursor; 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci err = callchain_cursor_append(cursor, cnode->ip, 265562306a36Sopenharmony_ci &cnode->ms, 265662306a36Sopenharmony_ci cnode->branch, 265762306a36Sopenharmony_ci &cnode->branch_flags, 265862306a36Sopenharmony_ci cnode->nr_loop_iter, 265962306a36Sopenharmony_ci cnode->iter_cycles, 266062306a36Sopenharmony_ci cnode->branch_from, 266162306a36Sopenharmony_ci cnode->srcline); 266262306a36Sopenharmony_ci if (err) 266362306a36Sopenharmony_ci return err; 266462306a36Sopenharmony_ci } 266562306a36Sopenharmony_ci return 0; 266662306a36Sopenharmony_ci} 266762306a36Sopenharmony_ci 266862306a36Sopenharmony_cistatic struct stitch_list *get_stitch_node(struct thread *thread) 266962306a36Sopenharmony_ci{ 267062306a36Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread); 267162306a36Sopenharmony_ci struct stitch_list *stitch_node; 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci if (!list_empty(&lbr_stitch->free_lists)) { 267462306a36Sopenharmony_ci stitch_node = list_first_entry(&lbr_stitch->free_lists, 267562306a36Sopenharmony_ci struct stitch_list, node); 267662306a36Sopenharmony_ci list_del(&stitch_node->node); 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci return stitch_node; 267962306a36Sopenharmony_ci } 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci return malloc(sizeof(struct stitch_list)); 268262306a36Sopenharmony_ci} 268362306a36Sopenharmony_ci 268462306a36Sopenharmony_cistatic bool has_stitched_lbr(struct thread *thread, 268562306a36Sopenharmony_ci struct perf_sample *cur, 268662306a36Sopenharmony_ci struct perf_sample *prev, 268762306a36Sopenharmony_ci unsigned int max_lbr, 268862306a36Sopenharmony_ci bool callee) 268962306a36Sopenharmony_ci{ 269062306a36Sopenharmony_ci struct branch_stack *cur_stack = cur->branch_stack; 269162306a36Sopenharmony_ci struct branch_entry *cur_entries = perf_sample__branch_entries(cur); 269262306a36Sopenharmony_ci struct branch_stack *prev_stack = prev->branch_stack; 269362306a36Sopenharmony_ci struct branch_entry *prev_entries = perf_sample__branch_entries(prev); 269462306a36Sopenharmony_ci struct lbr_stitch *lbr_stitch = thread__lbr_stitch(thread); 269562306a36Sopenharmony_ci int i, j, nr_identical_branches = 0; 269662306a36Sopenharmony_ci struct stitch_list *stitch_node; 269762306a36Sopenharmony_ci u64 cur_base, distance; 269862306a36Sopenharmony_ci 269962306a36Sopenharmony_ci if (!cur_stack || !prev_stack) 270062306a36Sopenharmony_ci return false; 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci /* Find the physical index of the base-of-stack for current sample. */ 270362306a36Sopenharmony_ci cur_base = max_lbr - cur_stack->nr + cur_stack->hw_idx + 1; 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci distance = (prev_stack->hw_idx > cur_base) ? (prev_stack->hw_idx - cur_base) : 270662306a36Sopenharmony_ci (max_lbr + prev_stack->hw_idx - cur_base); 270762306a36Sopenharmony_ci /* Previous sample has shorter stack. Nothing can be stitched. */ 270862306a36Sopenharmony_ci if (distance + 1 > prev_stack->nr) 270962306a36Sopenharmony_ci return false; 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci /* 271262306a36Sopenharmony_ci * Check if there are identical LBRs between two samples. 271362306a36Sopenharmony_ci * Identical LBRs must have same from, to and flags values. Also, 271462306a36Sopenharmony_ci * they have to be saved in the same LBR registers (same physical 271562306a36Sopenharmony_ci * index). 271662306a36Sopenharmony_ci * 271762306a36Sopenharmony_ci * Starts from the base-of-stack of current sample. 271862306a36Sopenharmony_ci */ 271962306a36Sopenharmony_ci for (i = distance, j = cur_stack->nr - 1; (i >= 0) && (j >= 0); i--, j--) { 272062306a36Sopenharmony_ci if ((prev_entries[i].from != cur_entries[j].from) || 272162306a36Sopenharmony_ci (prev_entries[i].to != cur_entries[j].to) || 272262306a36Sopenharmony_ci (prev_entries[i].flags.value != cur_entries[j].flags.value)) 272362306a36Sopenharmony_ci break; 272462306a36Sopenharmony_ci nr_identical_branches++; 272562306a36Sopenharmony_ci } 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci if (!nr_identical_branches) 272862306a36Sopenharmony_ci return false; 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci /* 273162306a36Sopenharmony_ci * Save the LBRs between the base-of-stack of previous sample 273262306a36Sopenharmony_ci * and the base-of-stack of current sample into lbr_stitch->lists. 273362306a36Sopenharmony_ci * These LBRs will be stitched later. 273462306a36Sopenharmony_ci */ 273562306a36Sopenharmony_ci for (i = prev_stack->nr - 1; i > (int)distance; i--) { 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci if (!lbr_stitch->prev_lbr_cursor[i].valid) 273862306a36Sopenharmony_ci continue; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci stitch_node = get_stitch_node(thread); 274162306a36Sopenharmony_ci if (!stitch_node) 274262306a36Sopenharmony_ci return false; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci memcpy(&stitch_node->cursor, &lbr_stitch->prev_lbr_cursor[i], 274562306a36Sopenharmony_ci sizeof(struct callchain_cursor_node)); 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci if (callee) 274862306a36Sopenharmony_ci list_add(&stitch_node->node, &lbr_stitch->lists); 274962306a36Sopenharmony_ci else 275062306a36Sopenharmony_ci list_add_tail(&stitch_node->node, &lbr_stitch->lists); 275162306a36Sopenharmony_ci } 275262306a36Sopenharmony_ci 275362306a36Sopenharmony_ci return true; 275462306a36Sopenharmony_ci} 275562306a36Sopenharmony_ci 275662306a36Sopenharmony_cistatic bool alloc_lbr_stitch(struct thread *thread, unsigned int max_lbr) 275762306a36Sopenharmony_ci{ 275862306a36Sopenharmony_ci if (thread__lbr_stitch(thread)) 275962306a36Sopenharmony_ci return true; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_ci thread__set_lbr_stitch(thread, zalloc(sizeof(struct lbr_stitch))); 276262306a36Sopenharmony_ci if (!thread__lbr_stitch(thread)) 276362306a36Sopenharmony_ci goto err; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci thread__lbr_stitch(thread)->prev_lbr_cursor = 276662306a36Sopenharmony_ci calloc(max_lbr + 1, sizeof(struct callchain_cursor_node)); 276762306a36Sopenharmony_ci if (!thread__lbr_stitch(thread)->prev_lbr_cursor) 276862306a36Sopenharmony_ci goto free_lbr_stitch; 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci INIT_LIST_HEAD(&thread__lbr_stitch(thread)->lists); 277162306a36Sopenharmony_ci INIT_LIST_HEAD(&thread__lbr_stitch(thread)->free_lists); 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci return true; 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_cifree_lbr_stitch: 277662306a36Sopenharmony_ci free(thread__lbr_stitch(thread)); 277762306a36Sopenharmony_ci thread__set_lbr_stitch(thread, NULL); 277862306a36Sopenharmony_cierr: 277962306a36Sopenharmony_ci pr_warning("Failed to allocate space for stitched LBRs. Disable LBR stitch\n"); 278062306a36Sopenharmony_ci thread__set_lbr_stitch_enable(thread, false); 278162306a36Sopenharmony_ci return false; 278262306a36Sopenharmony_ci} 278362306a36Sopenharmony_ci 278462306a36Sopenharmony_ci/* 278562306a36Sopenharmony_ci * Resolve LBR callstack chain sample 278662306a36Sopenharmony_ci * Return: 278762306a36Sopenharmony_ci * 1 on success get LBR callchain information 278862306a36Sopenharmony_ci * 0 no available LBR callchain information, should try fp 278962306a36Sopenharmony_ci * negative error code on other errors. 279062306a36Sopenharmony_ci */ 279162306a36Sopenharmony_cistatic int resolve_lbr_callchain_sample(struct thread *thread, 279262306a36Sopenharmony_ci struct callchain_cursor *cursor, 279362306a36Sopenharmony_ci struct perf_sample *sample, 279462306a36Sopenharmony_ci struct symbol **parent, 279562306a36Sopenharmony_ci struct addr_location *root_al, 279662306a36Sopenharmony_ci int max_stack, 279762306a36Sopenharmony_ci unsigned int max_lbr) 279862306a36Sopenharmony_ci{ 279962306a36Sopenharmony_ci bool callee = (callchain_param.order == ORDER_CALLEE); 280062306a36Sopenharmony_ci struct ip_callchain *chain = sample->callchain; 280162306a36Sopenharmony_ci int chain_nr = min(max_stack, (int)chain->nr), i; 280262306a36Sopenharmony_ci struct lbr_stitch *lbr_stitch; 280362306a36Sopenharmony_ci bool stitched_lbr = false; 280462306a36Sopenharmony_ci u64 branch_from = 0; 280562306a36Sopenharmony_ci int err; 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci for (i = 0; i < chain_nr; i++) { 280862306a36Sopenharmony_ci if (chain->ips[i] == PERF_CONTEXT_USER) 280962306a36Sopenharmony_ci break; 281062306a36Sopenharmony_ci } 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci /* LBR only affects the user callchain */ 281362306a36Sopenharmony_ci if (i == chain_nr) 281462306a36Sopenharmony_ci return 0; 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci if (thread__lbr_stitch_enable(thread) && !sample->no_hw_idx && 281762306a36Sopenharmony_ci (max_lbr > 0) && alloc_lbr_stitch(thread, max_lbr)) { 281862306a36Sopenharmony_ci lbr_stitch = thread__lbr_stitch(thread); 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci stitched_lbr = has_stitched_lbr(thread, sample, 282162306a36Sopenharmony_ci &lbr_stitch->prev_sample, 282262306a36Sopenharmony_ci max_lbr, callee); 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci if (!stitched_lbr && !list_empty(&lbr_stitch->lists)) { 282562306a36Sopenharmony_ci list_replace_init(&lbr_stitch->lists, 282662306a36Sopenharmony_ci &lbr_stitch->free_lists); 282762306a36Sopenharmony_ci } 282862306a36Sopenharmony_ci memcpy(&lbr_stitch->prev_sample, sample, sizeof(*sample)); 282962306a36Sopenharmony_ci } 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci if (callee) { 283262306a36Sopenharmony_ci /* Add kernel ip */ 283362306a36Sopenharmony_ci err = lbr_callchain_add_kernel_ip(thread, cursor, sample, 283462306a36Sopenharmony_ci parent, root_al, branch_from, 283562306a36Sopenharmony_ci true, i); 283662306a36Sopenharmony_ci if (err) 283762306a36Sopenharmony_ci goto error; 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci err = lbr_callchain_add_lbr_ip(thread, cursor, sample, parent, 284062306a36Sopenharmony_ci root_al, &branch_from, true); 284162306a36Sopenharmony_ci if (err) 284262306a36Sopenharmony_ci goto error; 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci if (stitched_lbr) { 284562306a36Sopenharmony_ci err = lbr_callchain_add_stitched_lbr_ip(thread, cursor); 284662306a36Sopenharmony_ci if (err) 284762306a36Sopenharmony_ci goto error; 284862306a36Sopenharmony_ci } 284962306a36Sopenharmony_ci 285062306a36Sopenharmony_ci } else { 285162306a36Sopenharmony_ci if (stitched_lbr) { 285262306a36Sopenharmony_ci err = lbr_callchain_add_stitched_lbr_ip(thread, cursor); 285362306a36Sopenharmony_ci if (err) 285462306a36Sopenharmony_ci goto error; 285562306a36Sopenharmony_ci } 285662306a36Sopenharmony_ci err = lbr_callchain_add_lbr_ip(thread, cursor, sample, parent, 285762306a36Sopenharmony_ci root_al, &branch_from, false); 285862306a36Sopenharmony_ci if (err) 285962306a36Sopenharmony_ci goto error; 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci /* Add kernel ip */ 286262306a36Sopenharmony_ci err = lbr_callchain_add_kernel_ip(thread, cursor, sample, 286362306a36Sopenharmony_ci parent, root_al, branch_from, 286462306a36Sopenharmony_ci false, i); 286562306a36Sopenharmony_ci if (err) 286662306a36Sopenharmony_ci goto error; 286762306a36Sopenharmony_ci } 286862306a36Sopenharmony_ci return 1; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_cierror: 287162306a36Sopenharmony_ci return (err < 0) ? err : 0; 287262306a36Sopenharmony_ci} 287362306a36Sopenharmony_ci 287462306a36Sopenharmony_cistatic int find_prev_cpumode(struct ip_callchain *chain, struct thread *thread, 287562306a36Sopenharmony_ci struct callchain_cursor *cursor, 287662306a36Sopenharmony_ci struct symbol **parent, 287762306a36Sopenharmony_ci struct addr_location *root_al, 287862306a36Sopenharmony_ci u8 *cpumode, int ent) 287962306a36Sopenharmony_ci{ 288062306a36Sopenharmony_ci int err = 0; 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci while (--ent >= 0) { 288362306a36Sopenharmony_ci u64 ip = chain->ips[ent]; 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_ci if (ip >= PERF_CONTEXT_MAX) { 288662306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 288762306a36Sopenharmony_ci root_al, cpumode, ip, 288862306a36Sopenharmony_ci false, NULL, NULL, 0); 288962306a36Sopenharmony_ci break; 289062306a36Sopenharmony_ci } 289162306a36Sopenharmony_ci } 289262306a36Sopenharmony_ci return err; 289362306a36Sopenharmony_ci} 289462306a36Sopenharmony_ci 289562306a36Sopenharmony_cistatic u64 get_leaf_frame_caller(struct perf_sample *sample, 289662306a36Sopenharmony_ci struct thread *thread, int usr_idx) 289762306a36Sopenharmony_ci{ 289862306a36Sopenharmony_ci if (machine__normalized_is(maps__machine(thread__maps(thread)), "arm64")) 289962306a36Sopenharmony_ci return get_leaf_frame_caller_aarch64(sample, thread, usr_idx); 290062306a36Sopenharmony_ci else 290162306a36Sopenharmony_ci return 0; 290262306a36Sopenharmony_ci} 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_cistatic int thread__resolve_callchain_sample(struct thread *thread, 290562306a36Sopenharmony_ci struct callchain_cursor *cursor, 290662306a36Sopenharmony_ci struct evsel *evsel, 290762306a36Sopenharmony_ci struct perf_sample *sample, 290862306a36Sopenharmony_ci struct symbol **parent, 290962306a36Sopenharmony_ci struct addr_location *root_al, 291062306a36Sopenharmony_ci int max_stack) 291162306a36Sopenharmony_ci{ 291262306a36Sopenharmony_ci struct branch_stack *branch = sample->branch_stack; 291362306a36Sopenharmony_ci struct branch_entry *entries = perf_sample__branch_entries(sample); 291462306a36Sopenharmony_ci struct ip_callchain *chain = sample->callchain; 291562306a36Sopenharmony_ci int chain_nr = 0; 291662306a36Sopenharmony_ci u8 cpumode = PERF_RECORD_MISC_USER; 291762306a36Sopenharmony_ci int i, j, err, nr_entries, usr_idx; 291862306a36Sopenharmony_ci int skip_idx = -1; 291962306a36Sopenharmony_ci int first_call = 0; 292062306a36Sopenharmony_ci u64 leaf_frame_caller; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci if (chain) 292362306a36Sopenharmony_ci chain_nr = chain->nr; 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci if (evsel__has_branch_callstack(evsel)) { 292662306a36Sopenharmony_ci struct perf_env *env = evsel__env(evsel); 292762306a36Sopenharmony_ci 292862306a36Sopenharmony_ci err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, 292962306a36Sopenharmony_ci root_al, max_stack, 293062306a36Sopenharmony_ci !env ? 0 : env->max_branches); 293162306a36Sopenharmony_ci if (err) 293262306a36Sopenharmony_ci return (err < 0) ? err : 0; 293362306a36Sopenharmony_ci } 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci /* 293662306a36Sopenharmony_ci * Based on DWARF debug information, some architectures skip 293762306a36Sopenharmony_ci * a callchain entry saved by the kernel. 293862306a36Sopenharmony_ci */ 293962306a36Sopenharmony_ci skip_idx = arch_skip_callchain_idx(thread, chain); 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_ci /* 294262306a36Sopenharmony_ci * Add branches to call stack for easier browsing. This gives 294362306a36Sopenharmony_ci * more context for a sample than just the callers. 294462306a36Sopenharmony_ci * 294562306a36Sopenharmony_ci * This uses individual histograms of paths compared to the 294662306a36Sopenharmony_ci * aggregated histograms the normal LBR mode uses. 294762306a36Sopenharmony_ci * 294862306a36Sopenharmony_ci * Limitations for now: 294962306a36Sopenharmony_ci * - No extra filters 295062306a36Sopenharmony_ci * - No annotations (should annotate somehow) 295162306a36Sopenharmony_ci */ 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci if (branch && callchain_param.branch_callstack) { 295462306a36Sopenharmony_ci int nr = min(max_stack, (int)branch->nr); 295562306a36Sopenharmony_ci struct branch_entry be[nr]; 295662306a36Sopenharmony_ci struct iterations iter[nr]; 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci if (branch->nr > PERF_MAX_BRANCH_DEPTH) { 295962306a36Sopenharmony_ci pr_warning("corrupted branch chain. skipping...\n"); 296062306a36Sopenharmony_ci goto check_calls; 296162306a36Sopenharmony_ci } 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 296462306a36Sopenharmony_ci if (callchain_param.order == ORDER_CALLEE) { 296562306a36Sopenharmony_ci be[i] = entries[i]; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci if (chain == NULL) 296862306a36Sopenharmony_ci continue; 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci /* 297162306a36Sopenharmony_ci * Check for overlap into the callchain. 297262306a36Sopenharmony_ci * The return address is one off compared to 297362306a36Sopenharmony_ci * the branch entry. To adjust for this 297462306a36Sopenharmony_ci * assume the calling instruction is not longer 297562306a36Sopenharmony_ci * than 8 bytes. 297662306a36Sopenharmony_ci */ 297762306a36Sopenharmony_ci if (i == skip_idx || 297862306a36Sopenharmony_ci chain->ips[first_call] >= PERF_CONTEXT_MAX) 297962306a36Sopenharmony_ci first_call++; 298062306a36Sopenharmony_ci else if (be[i].from < chain->ips[first_call] && 298162306a36Sopenharmony_ci be[i].from >= chain->ips[first_call] - 8) 298262306a36Sopenharmony_ci first_call++; 298362306a36Sopenharmony_ci } else 298462306a36Sopenharmony_ci be[i] = entries[branch->nr - i - 1]; 298562306a36Sopenharmony_ci } 298662306a36Sopenharmony_ci 298762306a36Sopenharmony_ci memset(iter, 0, sizeof(struct iterations) * nr); 298862306a36Sopenharmony_ci nr = remove_loops(be, nr, iter); 298962306a36Sopenharmony_ci 299062306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 299162306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 299262306a36Sopenharmony_ci root_al, 299362306a36Sopenharmony_ci NULL, be[i].to, 299462306a36Sopenharmony_ci true, &be[i].flags, 299562306a36Sopenharmony_ci NULL, be[i].from); 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci if (!err) 299862306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, root_al, 299962306a36Sopenharmony_ci NULL, be[i].from, 300062306a36Sopenharmony_ci true, &be[i].flags, 300162306a36Sopenharmony_ci &iter[i], 0); 300262306a36Sopenharmony_ci if (err == -EINVAL) 300362306a36Sopenharmony_ci break; 300462306a36Sopenharmony_ci if (err) 300562306a36Sopenharmony_ci return err; 300662306a36Sopenharmony_ci } 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci if (chain_nr == 0) 300962306a36Sopenharmony_ci return 0; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci chain_nr -= nr; 301262306a36Sopenharmony_ci } 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_cicheck_calls: 301562306a36Sopenharmony_ci if (chain && callchain_param.order != ORDER_CALLEE) { 301662306a36Sopenharmony_ci err = find_prev_cpumode(chain, thread, cursor, parent, root_al, 301762306a36Sopenharmony_ci &cpumode, chain->nr - first_call); 301862306a36Sopenharmony_ci if (err) 301962306a36Sopenharmony_ci return (err < 0) ? err : 0; 302062306a36Sopenharmony_ci } 302162306a36Sopenharmony_ci for (i = first_call, nr_entries = 0; 302262306a36Sopenharmony_ci i < chain_nr && nr_entries < max_stack; i++) { 302362306a36Sopenharmony_ci u64 ip; 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci if (callchain_param.order == ORDER_CALLEE) 302662306a36Sopenharmony_ci j = i; 302762306a36Sopenharmony_ci else 302862306a36Sopenharmony_ci j = chain->nr - i - 1; 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci#ifdef HAVE_SKIP_CALLCHAIN_IDX 303162306a36Sopenharmony_ci if (j == skip_idx) 303262306a36Sopenharmony_ci continue; 303362306a36Sopenharmony_ci#endif 303462306a36Sopenharmony_ci ip = chain->ips[j]; 303562306a36Sopenharmony_ci if (ip < PERF_CONTEXT_MAX) 303662306a36Sopenharmony_ci ++nr_entries; 303762306a36Sopenharmony_ci else if (callchain_param.order != ORDER_CALLEE) { 303862306a36Sopenharmony_ci err = find_prev_cpumode(chain, thread, cursor, parent, 303962306a36Sopenharmony_ci root_al, &cpumode, j); 304062306a36Sopenharmony_ci if (err) 304162306a36Sopenharmony_ci return (err < 0) ? err : 0; 304262306a36Sopenharmony_ci continue; 304362306a36Sopenharmony_ci } 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci /* 304662306a36Sopenharmony_ci * PERF_CONTEXT_USER allows us to locate where the user stack ends. 304762306a36Sopenharmony_ci * Depending on callchain_param.order and the position of PERF_CONTEXT_USER, 304862306a36Sopenharmony_ci * the index will be different in order to add the missing frame 304962306a36Sopenharmony_ci * at the right place. 305062306a36Sopenharmony_ci */ 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci usr_idx = callchain_param.order == ORDER_CALLEE ? j-2 : j-1; 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci if (usr_idx >= 0 && chain->ips[usr_idx] == PERF_CONTEXT_USER) { 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci leaf_frame_caller = get_leaf_frame_caller(sample, thread, usr_idx); 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* 305962306a36Sopenharmony_ci * check if leaf_frame_Caller != ip to not add the same 306062306a36Sopenharmony_ci * value twice. 306162306a36Sopenharmony_ci */ 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci if (leaf_frame_caller && leaf_frame_caller != ip) { 306462306a36Sopenharmony_ci 306562306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 306662306a36Sopenharmony_ci root_al, &cpumode, leaf_frame_caller, 306762306a36Sopenharmony_ci false, NULL, NULL, 0); 306862306a36Sopenharmony_ci if (err) 306962306a36Sopenharmony_ci return (err < 0) ? err : 0; 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci } 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci err = add_callchain_ip(thread, cursor, parent, 307462306a36Sopenharmony_ci root_al, &cpumode, ip, 307562306a36Sopenharmony_ci false, NULL, NULL, 0); 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci if (err) 307862306a36Sopenharmony_ci return (err < 0) ? err : 0; 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci return 0; 308262306a36Sopenharmony_ci} 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_cistatic int append_inlines(struct callchain_cursor *cursor, struct map_symbol *ms, u64 ip) 308562306a36Sopenharmony_ci{ 308662306a36Sopenharmony_ci struct symbol *sym = ms->sym; 308762306a36Sopenharmony_ci struct map *map = ms->map; 308862306a36Sopenharmony_ci struct inline_node *inline_node; 308962306a36Sopenharmony_ci struct inline_list *ilist; 309062306a36Sopenharmony_ci struct dso *dso; 309162306a36Sopenharmony_ci u64 addr; 309262306a36Sopenharmony_ci int ret = 1; 309362306a36Sopenharmony_ci struct map_symbol ilist_ms; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci if (!symbol_conf.inline_name || !map || !sym) 309662306a36Sopenharmony_ci return ret; 309762306a36Sopenharmony_ci 309862306a36Sopenharmony_ci addr = map__dso_map_ip(map, ip); 309962306a36Sopenharmony_ci addr = map__rip_2objdump(map, addr); 310062306a36Sopenharmony_ci dso = map__dso(map); 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci inline_node = inlines__tree_find(&dso->inlined_nodes, addr); 310362306a36Sopenharmony_ci if (!inline_node) { 310462306a36Sopenharmony_ci inline_node = dso__parse_addr_inlines(dso, addr, sym); 310562306a36Sopenharmony_ci if (!inline_node) 310662306a36Sopenharmony_ci return ret; 310762306a36Sopenharmony_ci inlines__tree_insert(&dso->inlined_nodes, inline_node); 310862306a36Sopenharmony_ci } 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci ilist_ms = (struct map_symbol) { 311162306a36Sopenharmony_ci .maps = maps__get(ms->maps), 311262306a36Sopenharmony_ci .map = map__get(map), 311362306a36Sopenharmony_ci }; 311462306a36Sopenharmony_ci list_for_each_entry(ilist, &inline_node->val, list) { 311562306a36Sopenharmony_ci ilist_ms.sym = ilist->symbol; 311662306a36Sopenharmony_ci ret = callchain_cursor_append(cursor, ip, &ilist_ms, false, 311762306a36Sopenharmony_ci NULL, 0, 0, 0, ilist->srcline); 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (ret != 0) 312062306a36Sopenharmony_ci return ret; 312162306a36Sopenharmony_ci } 312262306a36Sopenharmony_ci map__put(ilist_ms.map); 312362306a36Sopenharmony_ci maps__put(ilist_ms.maps); 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci return ret; 312662306a36Sopenharmony_ci} 312762306a36Sopenharmony_ci 312862306a36Sopenharmony_cistatic int unwind_entry(struct unwind_entry *entry, void *arg) 312962306a36Sopenharmony_ci{ 313062306a36Sopenharmony_ci struct callchain_cursor *cursor = arg; 313162306a36Sopenharmony_ci const char *srcline = NULL; 313262306a36Sopenharmony_ci u64 addr = entry->ip; 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_ci if (symbol_conf.hide_unresolved && entry->ms.sym == NULL) 313562306a36Sopenharmony_ci return 0; 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci if (append_inlines(cursor, &entry->ms, entry->ip) == 0) 313862306a36Sopenharmony_ci return 0; 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci /* 314162306a36Sopenharmony_ci * Convert entry->ip from a virtual address to an offset in 314262306a36Sopenharmony_ci * its corresponding binary. 314362306a36Sopenharmony_ci */ 314462306a36Sopenharmony_ci if (entry->ms.map) 314562306a36Sopenharmony_ci addr = map__dso_map_ip(entry->ms.map, entry->ip); 314662306a36Sopenharmony_ci 314762306a36Sopenharmony_ci srcline = callchain_srcline(&entry->ms, addr); 314862306a36Sopenharmony_ci return callchain_cursor_append(cursor, entry->ip, &entry->ms, 314962306a36Sopenharmony_ci false, NULL, 0, 0, 0, srcline); 315062306a36Sopenharmony_ci} 315162306a36Sopenharmony_ci 315262306a36Sopenharmony_cistatic int thread__resolve_callchain_unwind(struct thread *thread, 315362306a36Sopenharmony_ci struct callchain_cursor *cursor, 315462306a36Sopenharmony_ci struct evsel *evsel, 315562306a36Sopenharmony_ci struct perf_sample *sample, 315662306a36Sopenharmony_ci int max_stack) 315762306a36Sopenharmony_ci{ 315862306a36Sopenharmony_ci /* Can we do dwarf post unwind? */ 315962306a36Sopenharmony_ci if (!((evsel->core.attr.sample_type & PERF_SAMPLE_REGS_USER) && 316062306a36Sopenharmony_ci (evsel->core.attr.sample_type & PERF_SAMPLE_STACK_USER))) 316162306a36Sopenharmony_ci return 0; 316262306a36Sopenharmony_ci 316362306a36Sopenharmony_ci /* Bail out if nothing was captured. */ 316462306a36Sopenharmony_ci if ((!sample->user_regs.regs) || 316562306a36Sopenharmony_ci (!sample->user_stack.size)) 316662306a36Sopenharmony_ci return 0; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci return unwind__get_entries(unwind_entry, cursor, 316962306a36Sopenharmony_ci thread, sample, max_stack, false); 317062306a36Sopenharmony_ci} 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ciint thread__resolve_callchain(struct thread *thread, 317362306a36Sopenharmony_ci struct callchain_cursor *cursor, 317462306a36Sopenharmony_ci struct evsel *evsel, 317562306a36Sopenharmony_ci struct perf_sample *sample, 317662306a36Sopenharmony_ci struct symbol **parent, 317762306a36Sopenharmony_ci struct addr_location *root_al, 317862306a36Sopenharmony_ci int max_stack) 317962306a36Sopenharmony_ci{ 318062306a36Sopenharmony_ci int ret = 0; 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci if (cursor == NULL) 318362306a36Sopenharmony_ci return -ENOMEM; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci callchain_cursor_reset(cursor); 318662306a36Sopenharmony_ci 318762306a36Sopenharmony_ci if (callchain_param.order == ORDER_CALLEE) { 318862306a36Sopenharmony_ci ret = thread__resolve_callchain_sample(thread, cursor, 318962306a36Sopenharmony_ci evsel, sample, 319062306a36Sopenharmony_ci parent, root_al, 319162306a36Sopenharmony_ci max_stack); 319262306a36Sopenharmony_ci if (ret) 319362306a36Sopenharmony_ci return ret; 319462306a36Sopenharmony_ci ret = thread__resolve_callchain_unwind(thread, cursor, 319562306a36Sopenharmony_ci evsel, sample, 319662306a36Sopenharmony_ci max_stack); 319762306a36Sopenharmony_ci } else { 319862306a36Sopenharmony_ci ret = thread__resolve_callchain_unwind(thread, cursor, 319962306a36Sopenharmony_ci evsel, sample, 320062306a36Sopenharmony_ci max_stack); 320162306a36Sopenharmony_ci if (ret) 320262306a36Sopenharmony_ci return ret; 320362306a36Sopenharmony_ci ret = thread__resolve_callchain_sample(thread, cursor, 320462306a36Sopenharmony_ci evsel, sample, 320562306a36Sopenharmony_ci parent, root_al, 320662306a36Sopenharmony_ci max_stack); 320762306a36Sopenharmony_ci } 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci return ret; 321062306a36Sopenharmony_ci} 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ciint machine__for_each_thread(struct machine *machine, 321362306a36Sopenharmony_ci int (*fn)(struct thread *thread, void *p), 321462306a36Sopenharmony_ci void *priv) 321562306a36Sopenharmony_ci{ 321662306a36Sopenharmony_ci struct threads *threads; 321762306a36Sopenharmony_ci struct rb_node *nd; 321862306a36Sopenharmony_ci int rc = 0; 321962306a36Sopenharmony_ci int i; 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci for (i = 0; i < THREADS__TABLE_SIZE; i++) { 322262306a36Sopenharmony_ci threads = &machine->threads[i]; 322362306a36Sopenharmony_ci for (nd = rb_first_cached(&threads->entries); nd; 322462306a36Sopenharmony_ci nd = rb_next(nd)) { 322562306a36Sopenharmony_ci struct thread_rb_node *trb = rb_entry(nd, struct thread_rb_node, rb_node); 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci rc = fn(trb->thread, priv); 322862306a36Sopenharmony_ci if (rc != 0) 322962306a36Sopenharmony_ci return rc; 323062306a36Sopenharmony_ci } 323162306a36Sopenharmony_ci } 323262306a36Sopenharmony_ci return rc; 323362306a36Sopenharmony_ci} 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ciint machines__for_each_thread(struct machines *machines, 323662306a36Sopenharmony_ci int (*fn)(struct thread *thread, void *p), 323762306a36Sopenharmony_ci void *priv) 323862306a36Sopenharmony_ci{ 323962306a36Sopenharmony_ci struct rb_node *nd; 324062306a36Sopenharmony_ci int rc = 0; 324162306a36Sopenharmony_ci 324262306a36Sopenharmony_ci rc = machine__for_each_thread(&machines->host, fn, priv); 324362306a36Sopenharmony_ci if (rc != 0) 324462306a36Sopenharmony_ci return rc; 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_ci for (nd = rb_first_cached(&machines->guests); nd; nd = rb_next(nd)) { 324762306a36Sopenharmony_ci struct machine *machine = rb_entry(nd, struct machine, rb_node); 324862306a36Sopenharmony_ci 324962306a36Sopenharmony_ci rc = machine__for_each_thread(machine, fn, priv); 325062306a36Sopenharmony_ci if (rc != 0) 325162306a36Sopenharmony_ci return rc; 325262306a36Sopenharmony_ci } 325362306a36Sopenharmony_ci return rc; 325462306a36Sopenharmony_ci} 325562306a36Sopenharmony_ci 325662306a36Sopenharmony_cipid_t machine__get_current_tid(struct machine *machine, int cpu) 325762306a36Sopenharmony_ci{ 325862306a36Sopenharmony_ci if (cpu < 0 || (size_t)cpu >= machine->current_tid_sz) 325962306a36Sopenharmony_ci return -1; 326062306a36Sopenharmony_ci 326162306a36Sopenharmony_ci return machine->current_tid[cpu]; 326262306a36Sopenharmony_ci} 326362306a36Sopenharmony_ci 326462306a36Sopenharmony_ciint machine__set_current_tid(struct machine *machine, int cpu, pid_t pid, 326562306a36Sopenharmony_ci pid_t tid) 326662306a36Sopenharmony_ci{ 326762306a36Sopenharmony_ci struct thread *thread; 326862306a36Sopenharmony_ci const pid_t init_val = -1; 326962306a36Sopenharmony_ci 327062306a36Sopenharmony_ci if (cpu < 0) 327162306a36Sopenharmony_ci return -EINVAL; 327262306a36Sopenharmony_ci 327362306a36Sopenharmony_ci if (realloc_array_as_needed(machine->current_tid, 327462306a36Sopenharmony_ci machine->current_tid_sz, 327562306a36Sopenharmony_ci (unsigned int)cpu, 327662306a36Sopenharmony_ci &init_val)) 327762306a36Sopenharmony_ci return -ENOMEM; 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci machine->current_tid[cpu] = tid; 328062306a36Sopenharmony_ci 328162306a36Sopenharmony_ci thread = machine__findnew_thread(machine, pid, tid); 328262306a36Sopenharmony_ci if (!thread) 328362306a36Sopenharmony_ci return -ENOMEM; 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci thread__set_cpu(thread, cpu); 328662306a36Sopenharmony_ci thread__put(thread); 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci return 0; 328962306a36Sopenharmony_ci} 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci/* 329262306a36Sopenharmony_ci * Compares the raw arch string. N.B. see instead perf_env__arch() or 329362306a36Sopenharmony_ci * machine__normalized_is() if a normalized arch is needed. 329462306a36Sopenharmony_ci */ 329562306a36Sopenharmony_cibool machine__is(struct machine *machine, const char *arch) 329662306a36Sopenharmony_ci{ 329762306a36Sopenharmony_ci return machine && !strcmp(perf_env__raw_arch(machine->env), arch); 329862306a36Sopenharmony_ci} 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_cibool machine__normalized_is(struct machine *machine, const char *arch) 330162306a36Sopenharmony_ci{ 330262306a36Sopenharmony_ci return machine && !strcmp(perf_env__arch(machine->env), arch); 330362306a36Sopenharmony_ci} 330462306a36Sopenharmony_ci 330562306a36Sopenharmony_ciint machine__nr_cpus_avail(struct machine *machine) 330662306a36Sopenharmony_ci{ 330762306a36Sopenharmony_ci return machine ? perf_env__nr_cpus_avail(machine->env) : 0; 330862306a36Sopenharmony_ci} 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ciint machine__get_kernel_start(struct machine *machine) 331162306a36Sopenharmony_ci{ 331262306a36Sopenharmony_ci struct map *map = machine__kernel_map(machine); 331362306a36Sopenharmony_ci int err = 0; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci /* 331662306a36Sopenharmony_ci * The only addresses above 2^63 are kernel addresses of a 64-bit 331762306a36Sopenharmony_ci * kernel. Note that addresses are unsigned so that on a 32-bit system 331862306a36Sopenharmony_ci * all addresses including kernel addresses are less than 2^32. In 331962306a36Sopenharmony_ci * that case (32-bit system), if the kernel mapping is unknown, all 332062306a36Sopenharmony_ci * addresses will be assumed to be in user space - see 332162306a36Sopenharmony_ci * machine__kernel_ip(). 332262306a36Sopenharmony_ci */ 332362306a36Sopenharmony_ci machine->kernel_start = 1ULL << 63; 332462306a36Sopenharmony_ci if (map) { 332562306a36Sopenharmony_ci err = map__load(map); 332662306a36Sopenharmony_ci /* 332762306a36Sopenharmony_ci * On x86_64, PTI entry trampolines are less than the 332862306a36Sopenharmony_ci * start of kernel text, but still above 2^63. So leave 332962306a36Sopenharmony_ci * kernel_start = 1ULL << 63 for x86_64. 333062306a36Sopenharmony_ci */ 333162306a36Sopenharmony_ci if (!err && !machine__is(machine, "x86_64")) 333262306a36Sopenharmony_ci machine->kernel_start = map__start(map); 333362306a36Sopenharmony_ci } 333462306a36Sopenharmony_ci return err; 333562306a36Sopenharmony_ci} 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ciu8 machine__addr_cpumode(struct machine *machine, u8 cpumode, u64 addr) 333862306a36Sopenharmony_ci{ 333962306a36Sopenharmony_ci u8 addr_cpumode = cpumode; 334062306a36Sopenharmony_ci bool kernel_ip; 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci if (!machine->single_address_space) 334362306a36Sopenharmony_ci goto out; 334462306a36Sopenharmony_ci 334562306a36Sopenharmony_ci kernel_ip = machine__kernel_ip(machine, addr); 334662306a36Sopenharmony_ci switch (cpumode) { 334762306a36Sopenharmony_ci case PERF_RECORD_MISC_KERNEL: 334862306a36Sopenharmony_ci case PERF_RECORD_MISC_USER: 334962306a36Sopenharmony_ci addr_cpumode = kernel_ip ? PERF_RECORD_MISC_KERNEL : 335062306a36Sopenharmony_ci PERF_RECORD_MISC_USER; 335162306a36Sopenharmony_ci break; 335262306a36Sopenharmony_ci case PERF_RECORD_MISC_GUEST_KERNEL: 335362306a36Sopenharmony_ci case PERF_RECORD_MISC_GUEST_USER: 335462306a36Sopenharmony_ci addr_cpumode = kernel_ip ? PERF_RECORD_MISC_GUEST_KERNEL : 335562306a36Sopenharmony_ci PERF_RECORD_MISC_GUEST_USER; 335662306a36Sopenharmony_ci break; 335762306a36Sopenharmony_ci default: 335862306a36Sopenharmony_ci break; 335962306a36Sopenharmony_ci } 336062306a36Sopenharmony_ciout: 336162306a36Sopenharmony_ci return addr_cpumode; 336262306a36Sopenharmony_ci} 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_cistruct dso *machine__findnew_dso_id(struct machine *machine, const char *filename, struct dso_id *id) 336562306a36Sopenharmony_ci{ 336662306a36Sopenharmony_ci return dsos__findnew_id(&machine->dsos, filename, id); 336762306a36Sopenharmony_ci} 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_cistruct dso *machine__findnew_dso(struct machine *machine, const char *filename) 337062306a36Sopenharmony_ci{ 337162306a36Sopenharmony_ci return machine__findnew_dso_id(machine, filename, NULL); 337262306a36Sopenharmony_ci} 337362306a36Sopenharmony_ci 337462306a36Sopenharmony_cichar *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp) 337562306a36Sopenharmony_ci{ 337662306a36Sopenharmony_ci struct machine *machine = vmachine; 337762306a36Sopenharmony_ci struct map *map; 337862306a36Sopenharmony_ci struct symbol *sym = machine__find_kernel_symbol(machine, *addrp, &map); 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci if (sym == NULL) 338162306a36Sopenharmony_ci return NULL; 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ci *modp = __map__is_kmodule(map) ? (char *)map__dso(map)->short_name : NULL; 338462306a36Sopenharmony_ci *addrp = map__unmap_ip(map, sym->start); 338562306a36Sopenharmony_ci return sym->name; 338662306a36Sopenharmony_ci} 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ciint machine__for_each_dso(struct machine *machine, machine__dso_t fn, void *priv) 338962306a36Sopenharmony_ci{ 339062306a36Sopenharmony_ci struct dso *pos; 339162306a36Sopenharmony_ci int err = 0; 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci list_for_each_entry(pos, &machine->dsos.head, node) { 339462306a36Sopenharmony_ci if (fn(pos, machine, priv)) 339562306a36Sopenharmony_ci err = -1; 339662306a36Sopenharmony_ci } 339762306a36Sopenharmony_ci return err; 339862306a36Sopenharmony_ci} 339962306a36Sopenharmony_ci 340062306a36Sopenharmony_ciint machine__for_each_kernel_map(struct machine *machine, machine__map_t fn, void *priv) 340162306a36Sopenharmony_ci{ 340262306a36Sopenharmony_ci struct maps *maps = machine__kernel_maps(machine); 340362306a36Sopenharmony_ci struct map_rb_node *pos; 340462306a36Sopenharmony_ci int err = 0; 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci maps__for_each_entry(maps, pos) { 340762306a36Sopenharmony_ci err = fn(pos->map, priv); 340862306a36Sopenharmony_ci if (err != 0) { 340962306a36Sopenharmony_ci break; 341062306a36Sopenharmony_ci } 341162306a36Sopenharmony_ci } 341262306a36Sopenharmony_ci return err; 341362306a36Sopenharmony_ci} 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_cibool machine__is_lock_function(struct machine *machine, u64 addr) 341662306a36Sopenharmony_ci{ 341762306a36Sopenharmony_ci if (!machine->sched.text_start) { 341862306a36Sopenharmony_ci struct map *kmap; 341962306a36Sopenharmony_ci struct symbol *sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_start", &kmap); 342062306a36Sopenharmony_ci 342162306a36Sopenharmony_ci if (!sym) { 342262306a36Sopenharmony_ci /* to avoid retry */ 342362306a36Sopenharmony_ci machine->sched.text_start = 1; 342462306a36Sopenharmony_ci return false; 342562306a36Sopenharmony_ci } 342662306a36Sopenharmony_ci 342762306a36Sopenharmony_ci machine->sched.text_start = map__unmap_ip(kmap, sym->start); 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci /* should not fail from here */ 343062306a36Sopenharmony_ci sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_end", &kmap); 343162306a36Sopenharmony_ci machine->sched.text_end = map__unmap_ip(kmap, sym->start); 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_start", &kmap); 343462306a36Sopenharmony_ci machine->lock.text_start = map__unmap_ip(kmap, sym->start); 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap); 343762306a36Sopenharmony_ci machine->lock.text_end = map__unmap_ip(kmap, sym->start); 343862306a36Sopenharmony_ci } 343962306a36Sopenharmony_ci 344062306a36Sopenharmony_ci /* failed to get kernel symbols */ 344162306a36Sopenharmony_ci if (machine->sched.text_start == 1) 344262306a36Sopenharmony_ci return false; 344362306a36Sopenharmony_ci 344462306a36Sopenharmony_ci /* mutex and rwsem functions are in sched text section */ 344562306a36Sopenharmony_ci if (machine->sched.text_start <= addr && addr < machine->sched.text_end) 344662306a36Sopenharmony_ci return true; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci /* spinlock functions are in lock text section */ 344962306a36Sopenharmony_ci if (machine->lock.text_start <= addr && addr < machine->lock.text_end) 345062306a36Sopenharmony_ci return true; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci return false; 345362306a36Sopenharmony_ci} 3454