1*1a12ed09SIan Rogers // SPDX-License-Identifier: GPL-2.0 2*1a12ed09SIan Rogers #include "debug.h" 3*1a12ed09SIan Rogers #include "env.h" 4*1a12ed09SIan Rogers #include "lock-contention.h" 5*1a12ed09SIan Rogers #include "machine.h" 6*1a12ed09SIan Rogers #include "symbol.h" 7*1a12ed09SIan Rogers 8*1a12ed09SIan Rogers #include <limits.h> 9*1a12ed09SIan Rogers #include <string.h> 10*1a12ed09SIan Rogers 11*1a12ed09SIan Rogers #include <linux/hash.h> 12*1a12ed09SIan Rogers #include <linux/zalloc.h> 13*1a12ed09SIan Rogers 14*1a12ed09SIan Rogers #define __lockhashfn(key) hash_long((unsigned long)key, LOCKHASH_BITS) 15*1a12ed09SIan Rogers #define lockhashentry(key) (lockhash_table + __lockhashfn((key))) 16*1a12ed09SIan Rogers 17*1a12ed09SIan Rogers struct callstack_filter { 18*1a12ed09SIan Rogers struct list_head list; 19*1a12ed09SIan Rogers char name[]; 20*1a12ed09SIan Rogers }; 21*1a12ed09SIan Rogers 22*1a12ed09SIan Rogers static LIST_HEAD(callstack_filters); 23*1a12ed09SIan Rogers struct hlist_head *lockhash_table; 24*1a12ed09SIan Rogers 25*1a12ed09SIan Rogers int parse_call_stack(const struct option *opt __maybe_unused, const char *str, 26*1a12ed09SIan Rogers int unset __maybe_unused) 27*1a12ed09SIan Rogers { 28*1a12ed09SIan Rogers char *s, *tmp, *tok; 29*1a12ed09SIan Rogers int ret = 0; 30*1a12ed09SIan Rogers 31*1a12ed09SIan Rogers s = strdup(str); 32*1a12ed09SIan Rogers if (s == NULL) 33*1a12ed09SIan Rogers return -1; 34*1a12ed09SIan Rogers 35*1a12ed09SIan Rogers for (tok = strtok_r(s, ", ", &tmp); tok; tok = strtok_r(NULL, ", ", &tmp)) { 36*1a12ed09SIan Rogers struct callstack_filter *entry; 37*1a12ed09SIan Rogers 38*1a12ed09SIan Rogers entry = malloc(sizeof(*entry) + strlen(tok) + 1); 39*1a12ed09SIan Rogers if (entry == NULL) { 40*1a12ed09SIan Rogers pr_err("Memory allocation failure\n"); 41*1a12ed09SIan Rogers free(s); 42*1a12ed09SIan Rogers return -1; 43*1a12ed09SIan Rogers } 44*1a12ed09SIan Rogers 45*1a12ed09SIan Rogers strcpy(entry->name, tok); 46*1a12ed09SIan Rogers list_add_tail(&entry->list, &callstack_filters); 47*1a12ed09SIan Rogers } 48*1a12ed09SIan Rogers 49*1a12ed09SIan Rogers free(s); 50*1a12ed09SIan Rogers return ret; 51*1a12ed09SIan Rogers } 52*1a12ed09SIan Rogers 53*1a12ed09SIan Rogers bool needs_callstack(void) 54*1a12ed09SIan Rogers { 55*1a12ed09SIan Rogers return !list_empty(&callstack_filters); 56*1a12ed09SIan Rogers } 57*1a12ed09SIan Rogers 58*1a12ed09SIan Rogers struct lock_stat *lock_stat_find(u64 addr) 59*1a12ed09SIan Rogers { 60*1a12ed09SIan Rogers struct hlist_head *entry = lockhashentry(addr); 61*1a12ed09SIan Rogers struct lock_stat *ret; 62*1a12ed09SIan Rogers 63*1a12ed09SIan Rogers hlist_for_each_entry(ret, entry, hash_entry) { 64*1a12ed09SIan Rogers if (ret->addr == addr) 65*1a12ed09SIan Rogers return ret; 66*1a12ed09SIan Rogers } 67*1a12ed09SIan Rogers return NULL; 68*1a12ed09SIan Rogers } 69*1a12ed09SIan Rogers 70*1a12ed09SIan Rogers struct lock_stat *lock_stat_findnew(u64 addr, const char *name, int flags) 71*1a12ed09SIan Rogers { 72*1a12ed09SIan Rogers struct hlist_head *entry = lockhashentry(addr); 73*1a12ed09SIan Rogers struct lock_stat *ret, *new; 74*1a12ed09SIan Rogers 75*1a12ed09SIan Rogers hlist_for_each_entry(ret, entry, hash_entry) { 76*1a12ed09SIan Rogers if (ret->addr == addr) 77*1a12ed09SIan Rogers return ret; 78*1a12ed09SIan Rogers } 79*1a12ed09SIan Rogers 80*1a12ed09SIan Rogers new = zalloc(sizeof(struct lock_stat)); 81*1a12ed09SIan Rogers if (!new) 82*1a12ed09SIan Rogers goto alloc_failed; 83*1a12ed09SIan Rogers 84*1a12ed09SIan Rogers new->addr = addr; 85*1a12ed09SIan Rogers new->name = strdup(name); 86*1a12ed09SIan Rogers if (!new->name) { 87*1a12ed09SIan Rogers free(new); 88*1a12ed09SIan Rogers goto alloc_failed; 89*1a12ed09SIan Rogers } 90*1a12ed09SIan Rogers 91*1a12ed09SIan Rogers new->flags = flags; 92*1a12ed09SIan Rogers new->wait_time_min = ULLONG_MAX; 93*1a12ed09SIan Rogers 94*1a12ed09SIan Rogers hlist_add_head(&new->hash_entry, entry); 95*1a12ed09SIan Rogers return new; 96*1a12ed09SIan Rogers 97*1a12ed09SIan Rogers alloc_failed: 98*1a12ed09SIan Rogers pr_err("memory allocation failed\n"); 99*1a12ed09SIan Rogers return NULL; 100*1a12ed09SIan Rogers } 101*1a12ed09SIan Rogers 102*1a12ed09SIan Rogers bool match_callstack_filter(struct machine *machine, u64 *callstack, int max_stack_depth) 103*1a12ed09SIan Rogers { 104*1a12ed09SIan Rogers struct map *kmap; 105*1a12ed09SIan Rogers struct symbol *sym; 106*1a12ed09SIan Rogers u64 ip; 107*1a12ed09SIan Rogers const char *arch = perf_env__arch(machine->env); 108*1a12ed09SIan Rogers 109*1a12ed09SIan Rogers if (list_empty(&callstack_filters)) 110*1a12ed09SIan Rogers return true; 111*1a12ed09SIan Rogers 112*1a12ed09SIan Rogers for (int i = 0; i < max_stack_depth; i++) { 113*1a12ed09SIan Rogers struct callstack_filter *filter; 114*1a12ed09SIan Rogers 115*1a12ed09SIan Rogers /* 116*1a12ed09SIan Rogers * In powerpc, the callchain saved by kernel always includes 117*1a12ed09SIan Rogers * first three entries as the NIP (next instruction pointer), 118*1a12ed09SIan Rogers * LR (link register), and the contents of LR save area in the 119*1a12ed09SIan Rogers * second stack frame. In certain scenarios its possible to have 120*1a12ed09SIan Rogers * invalid kernel instruction addresses in either LR or the second 121*1a12ed09SIan Rogers * stack frame's LR. In that case, kernel will store that address as 122*1a12ed09SIan Rogers * zero. 123*1a12ed09SIan Rogers * 124*1a12ed09SIan Rogers * The below check will continue to look into callstack, 125*1a12ed09SIan Rogers * incase first or second callstack index entry has 0 126*1a12ed09SIan Rogers * address for powerpc. 127*1a12ed09SIan Rogers */ 128*1a12ed09SIan Rogers if (!callstack || (!callstack[i] && (strcmp(arch, "powerpc") || 129*1a12ed09SIan Rogers (i != 1 && i != 2)))) 130*1a12ed09SIan Rogers break; 131*1a12ed09SIan Rogers 132*1a12ed09SIan Rogers ip = callstack[i]; 133*1a12ed09SIan Rogers sym = machine__find_kernel_symbol(machine, ip, &kmap); 134*1a12ed09SIan Rogers if (sym == NULL) 135*1a12ed09SIan Rogers continue; 136*1a12ed09SIan Rogers 137*1a12ed09SIan Rogers list_for_each_entry(filter, &callstack_filters, list) { 138*1a12ed09SIan Rogers if (strstr(sym->name, filter->name)) 139*1a12ed09SIan Rogers return true; 140*1a12ed09SIan Rogers } 141*1a12ed09SIan Rogers } 142*1a12ed09SIan Rogers return false; 143*1a12ed09SIan Rogers } 144