1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 28637c099SIngo Molnar /* 38637c099SIngo Molnar * kernel/stacktrace.c 48637c099SIngo Molnar * 58637c099SIngo Molnar * Stack trace management functions 68637c099SIngo Molnar * 78637c099SIngo Molnar * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <[email protected]> 88637c099SIngo Molnar */ 9214d8ca6SThomas Gleixner #include <linux/sched/task_stack.h> 10214d8ca6SThomas Gleixner #include <linux/sched/debug.h> 118637c099SIngo Molnar #include <linux/sched.h> 129212ddb5SIngo Molnar #include <linux/kernel.h> 139984de1aSPaul Gortmaker #include <linux/export.h> 148637c099SIngo Molnar #include <linux/kallsyms.h> 158637c099SIngo Molnar #include <linux/stacktrace.h> 16*f39f21b3SMarco Elver #include <linux/interrupt.h> 178637c099SIngo Molnar 18e9b98e16SThomas Gleixner /** 19e9b98e16SThomas Gleixner * stack_trace_print - Print the entries in the stack trace 20e9b98e16SThomas Gleixner * @entries: Pointer to storage array 21e9b98e16SThomas Gleixner * @nr_entries: Number of entries in the storage array 22e9b98e16SThomas Gleixner * @spaces: Number of leading spaces to print 23e9b98e16SThomas Gleixner */ 24a2970421SBart Van Assche void stack_trace_print(const unsigned long *entries, unsigned int nr_entries, 25e9b98e16SThomas Gleixner int spaces) 268637c099SIngo Molnar { 27e9b98e16SThomas Gleixner unsigned int i; 288637c099SIngo Molnar 29e9b98e16SThomas Gleixner if (WARN_ON(!entries)) 30bfeeeeb9SJohannes Berg return; 31bfeeeeb9SJohannes Berg 32e9b98e16SThomas Gleixner for (i = 0; i < nr_entries; i++) 33e9b98e16SThomas Gleixner printk("%*c%pS\n", 1 + spaces, ' ', (void *)entries[i]); 34e9b98e16SThomas Gleixner } 35e9b98e16SThomas Gleixner EXPORT_SYMBOL_GPL(stack_trace_print); 36e9b98e16SThomas Gleixner 37e9b98e16SThomas Gleixner /** 38e9b98e16SThomas Gleixner * stack_trace_snprint - Print the entries in the stack trace into a buffer 39e9b98e16SThomas Gleixner * @buf: Pointer to the print buffer 40e9b98e16SThomas Gleixner * @size: Size of the print buffer 41e9b98e16SThomas Gleixner * @entries: Pointer to storage array 42e9b98e16SThomas Gleixner * @nr_entries: Number of entries in the storage array 43e9b98e16SThomas Gleixner * @spaces: Number of leading spaces to print 44e9b98e16SThomas Gleixner * 45e9b98e16SThomas Gleixner * Return: Number of bytes printed. 46e9b98e16SThomas Gleixner */ 47a2970421SBart Van Assche int stack_trace_snprint(char *buf, size_t size, const unsigned long *entries, 48e9b98e16SThomas Gleixner unsigned int nr_entries, int spaces) 499a92a6ceSJoonsoo Kim { 50e9b98e16SThomas Gleixner unsigned int generated, i, total = 0; 519a92a6ceSJoonsoo Kim 52e9b98e16SThomas Gleixner if (WARN_ON(!entries)) 539a92a6ceSJoonsoo Kim return 0; 549a92a6ceSJoonsoo Kim 55e9b98e16SThomas Gleixner for (i = 0; i < nr_entries && size; i++) { 56bfeda41dSOmar Sandoval generated = snprintf(buf, size, "%*c%pS\n", 1 + spaces, ' ', 57e9b98e16SThomas Gleixner (void *)entries[i]); 589a92a6ceSJoonsoo Kim 599a92a6ceSJoonsoo Kim total += generated; 609a92a6ceSJoonsoo Kim if (generated >= size) { 619a92a6ceSJoonsoo Kim buf += size; 629a92a6ceSJoonsoo Kim size = 0; 639a92a6ceSJoonsoo Kim } else { 649a92a6ceSJoonsoo Kim buf += generated; 659a92a6ceSJoonsoo Kim size -= generated; 669a92a6ceSJoonsoo Kim } 679a92a6ceSJoonsoo Kim } 689a92a6ceSJoonsoo Kim 699a92a6ceSJoonsoo Kim return total; 709a92a6ceSJoonsoo Kim } 71e9b98e16SThomas Gleixner EXPORT_SYMBOL_GPL(stack_trace_snprint); 72e9b98e16SThomas Gleixner 73214d8ca6SThomas Gleixner #ifdef CONFIG_ARCH_STACKWALK 74214d8ca6SThomas Gleixner 75214d8ca6SThomas Gleixner struct stacktrace_cookie { 76214d8ca6SThomas Gleixner unsigned long *store; 77214d8ca6SThomas Gleixner unsigned int size; 78214d8ca6SThomas Gleixner unsigned int skip; 79214d8ca6SThomas Gleixner unsigned int len; 80214d8ca6SThomas Gleixner }; 81214d8ca6SThomas Gleixner 82264c03a2SMark Brown static bool stack_trace_consume_entry(void *cookie, unsigned long addr) 83214d8ca6SThomas Gleixner { 84214d8ca6SThomas Gleixner struct stacktrace_cookie *c = cookie; 85214d8ca6SThomas Gleixner 86214d8ca6SThomas Gleixner if (c->len >= c->size) 87214d8ca6SThomas Gleixner return false; 88214d8ca6SThomas Gleixner 89214d8ca6SThomas Gleixner if (c->skip > 0) { 90214d8ca6SThomas Gleixner c->skip--; 91214d8ca6SThomas Gleixner return true; 92214d8ca6SThomas Gleixner } 93214d8ca6SThomas Gleixner c->store[c->len++] = addr; 94214d8ca6SThomas Gleixner return c->len < c->size; 95214d8ca6SThomas Gleixner } 96214d8ca6SThomas Gleixner 97264c03a2SMark Brown static bool stack_trace_consume_entry_nosched(void *cookie, unsigned long addr) 98214d8ca6SThomas Gleixner { 99214d8ca6SThomas Gleixner if (in_sched_functions(addr)) 100214d8ca6SThomas Gleixner return true; 101264c03a2SMark Brown return stack_trace_consume_entry(cookie, addr); 102214d8ca6SThomas Gleixner } 103214d8ca6SThomas Gleixner 104214d8ca6SThomas Gleixner /** 105214d8ca6SThomas Gleixner * stack_trace_save - Save a stack trace into a storage array 106214d8ca6SThomas Gleixner * @store: Pointer to storage array 107214d8ca6SThomas Gleixner * @size: Size of the storage array 108214d8ca6SThomas Gleixner * @skipnr: Number of entries to skip at the start of the stack trace 109214d8ca6SThomas Gleixner * 110214d8ca6SThomas Gleixner * Return: Number of trace entries stored. 111214d8ca6SThomas Gleixner */ 112214d8ca6SThomas Gleixner unsigned int stack_trace_save(unsigned long *store, unsigned int size, 113214d8ca6SThomas Gleixner unsigned int skipnr) 114214d8ca6SThomas Gleixner { 115214d8ca6SThomas Gleixner stack_trace_consume_fn consume_entry = stack_trace_consume_entry; 116214d8ca6SThomas Gleixner struct stacktrace_cookie c = { 117214d8ca6SThomas Gleixner .store = store, 118214d8ca6SThomas Gleixner .size = size, 119214d8ca6SThomas Gleixner .skip = skipnr + 1, 120214d8ca6SThomas Gleixner }; 121214d8ca6SThomas Gleixner 122214d8ca6SThomas Gleixner arch_stack_walk(consume_entry, &c, current, NULL); 123214d8ca6SThomas Gleixner return c.len; 124214d8ca6SThomas Gleixner } 125214d8ca6SThomas Gleixner EXPORT_SYMBOL_GPL(stack_trace_save); 126214d8ca6SThomas Gleixner 127214d8ca6SThomas Gleixner /** 128214d8ca6SThomas Gleixner * stack_trace_save_tsk - Save a task stack trace into a storage array 129214d8ca6SThomas Gleixner * @task: The task to examine 130214d8ca6SThomas Gleixner * @store: Pointer to storage array 131214d8ca6SThomas Gleixner * @size: Size of the storage array 132214d8ca6SThomas Gleixner * @skipnr: Number of entries to skip at the start of the stack trace 133214d8ca6SThomas Gleixner * 134214d8ca6SThomas Gleixner * Return: Number of trace entries stored. 135214d8ca6SThomas Gleixner */ 136214d8ca6SThomas Gleixner unsigned int stack_trace_save_tsk(struct task_struct *tsk, unsigned long *store, 137214d8ca6SThomas Gleixner unsigned int size, unsigned int skipnr) 138214d8ca6SThomas Gleixner { 139214d8ca6SThomas Gleixner stack_trace_consume_fn consume_entry = stack_trace_consume_entry_nosched; 140214d8ca6SThomas Gleixner struct stacktrace_cookie c = { 141214d8ca6SThomas Gleixner .store = store, 142214d8ca6SThomas Gleixner .size = size, 143b0c51f15SJiri Slaby /* skip this function if they are tracing us */ 1444b48512cSJiri Slaby .skip = skipnr + (current == tsk), 145214d8ca6SThomas Gleixner }; 146214d8ca6SThomas Gleixner 147214d8ca6SThomas Gleixner if (!try_get_task_stack(tsk)) 148214d8ca6SThomas Gleixner return 0; 149214d8ca6SThomas Gleixner 150214d8ca6SThomas Gleixner arch_stack_walk(consume_entry, &c, tsk, NULL); 151214d8ca6SThomas Gleixner put_task_stack(tsk); 152214d8ca6SThomas Gleixner return c.len; 153214d8ca6SThomas Gleixner } 154214d8ca6SThomas Gleixner 155214d8ca6SThomas Gleixner /** 156214d8ca6SThomas Gleixner * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array 157214d8ca6SThomas Gleixner * @regs: Pointer to pt_regs to examine 158214d8ca6SThomas Gleixner * @store: Pointer to storage array 159214d8ca6SThomas Gleixner * @size: Size of the storage array 160214d8ca6SThomas Gleixner * @skipnr: Number of entries to skip at the start of the stack trace 161214d8ca6SThomas Gleixner * 162214d8ca6SThomas Gleixner * Return: Number of trace entries stored. 163214d8ca6SThomas Gleixner */ 164214d8ca6SThomas Gleixner unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store, 165214d8ca6SThomas Gleixner unsigned int size, unsigned int skipnr) 166214d8ca6SThomas Gleixner { 167214d8ca6SThomas Gleixner stack_trace_consume_fn consume_entry = stack_trace_consume_entry; 168214d8ca6SThomas Gleixner struct stacktrace_cookie c = { 169214d8ca6SThomas Gleixner .store = store, 170214d8ca6SThomas Gleixner .size = size, 171214d8ca6SThomas Gleixner .skip = skipnr, 172214d8ca6SThomas Gleixner }; 173214d8ca6SThomas Gleixner 174214d8ca6SThomas Gleixner arch_stack_walk(consume_entry, &c, current, regs); 175214d8ca6SThomas Gleixner return c.len; 176214d8ca6SThomas Gleixner } 177214d8ca6SThomas Gleixner 178214d8ca6SThomas Gleixner #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE 179214d8ca6SThomas Gleixner /** 180214d8ca6SThomas Gleixner * stack_trace_save_tsk_reliable - Save task stack with verification 181214d8ca6SThomas Gleixner * @tsk: Pointer to the task to examine 182214d8ca6SThomas Gleixner * @store: Pointer to storage array 183214d8ca6SThomas Gleixner * @size: Size of the storage array 184214d8ca6SThomas Gleixner * 185214d8ca6SThomas Gleixner * Return: An error if it detects any unreliable features of the 186214d8ca6SThomas Gleixner * stack. Otherwise it guarantees that the stack trace is 187214d8ca6SThomas Gleixner * reliable and returns the number of entries stored. 188214d8ca6SThomas Gleixner * 189214d8ca6SThomas Gleixner * If the task is not 'current', the caller *must* ensure the task is inactive. 190214d8ca6SThomas Gleixner */ 191214d8ca6SThomas Gleixner int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store, 192214d8ca6SThomas Gleixner unsigned int size) 193214d8ca6SThomas Gleixner { 194214d8ca6SThomas Gleixner stack_trace_consume_fn consume_entry = stack_trace_consume_entry; 195214d8ca6SThomas Gleixner struct stacktrace_cookie c = { 196214d8ca6SThomas Gleixner .store = store, 197214d8ca6SThomas Gleixner .size = size, 198214d8ca6SThomas Gleixner }; 199214d8ca6SThomas Gleixner int ret; 200214d8ca6SThomas Gleixner 201214d8ca6SThomas Gleixner /* 202214d8ca6SThomas Gleixner * If the task doesn't have a stack (e.g., a zombie), the stack is 203214d8ca6SThomas Gleixner * "reliably" empty. 204214d8ca6SThomas Gleixner */ 205214d8ca6SThomas Gleixner if (!try_get_task_stack(tsk)) 206214d8ca6SThomas Gleixner return 0; 207214d8ca6SThomas Gleixner 208214d8ca6SThomas Gleixner ret = arch_stack_walk_reliable(consume_entry, &c, tsk); 209214d8ca6SThomas Gleixner put_task_stack(tsk); 2107eaf51a2SJoe Lawrence return ret ? ret : c.len; 211214d8ca6SThomas Gleixner } 212214d8ca6SThomas Gleixner #endif 213214d8ca6SThomas Gleixner 214214d8ca6SThomas Gleixner #ifdef CONFIG_USER_STACKTRACE_SUPPORT 215214d8ca6SThomas Gleixner /** 216214d8ca6SThomas Gleixner * stack_trace_save_user - Save a user space stack trace into a storage array 217214d8ca6SThomas Gleixner * @store: Pointer to storage array 218214d8ca6SThomas Gleixner * @size: Size of the storage array 219214d8ca6SThomas Gleixner * 220214d8ca6SThomas Gleixner * Return: Number of trace entries stored. 221214d8ca6SThomas Gleixner */ 222214d8ca6SThomas Gleixner unsigned int stack_trace_save_user(unsigned long *store, unsigned int size) 223214d8ca6SThomas Gleixner { 224214d8ca6SThomas Gleixner stack_trace_consume_fn consume_entry = stack_trace_consume_entry; 225214d8ca6SThomas Gleixner struct stacktrace_cookie c = { 226214d8ca6SThomas Gleixner .store = store, 227214d8ca6SThomas Gleixner .size = size, 228214d8ca6SThomas Gleixner }; 229cac9b9a4SPeter Zijlstra mm_segment_t fs; 230214d8ca6SThomas Gleixner 231214d8ca6SThomas Gleixner /* Trace user stack if not a kernel thread */ 2327e8e6816SThomas Gleixner if (current->flags & PF_KTHREAD) 233214d8ca6SThomas Gleixner return 0; 234214d8ca6SThomas Gleixner 2353d13f313SChristoph Hellwig fs = force_uaccess_begin(); 236214d8ca6SThomas Gleixner arch_stack_walk_user(consume_entry, &c, task_pt_regs(current)); 2373d13f313SChristoph Hellwig force_uaccess_end(fs); 238cac9b9a4SPeter Zijlstra 239214d8ca6SThomas Gleixner return c.len; 240214d8ca6SThomas Gleixner } 241214d8ca6SThomas Gleixner #endif 242214d8ca6SThomas Gleixner 243214d8ca6SThomas Gleixner #else /* CONFIG_ARCH_STACKWALK */ 244214d8ca6SThomas Gleixner 2459212ddb5SIngo Molnar /* 246af085d90SJosh Poimboeuf * Architectures that do not implement save_stack_trace_*() 247af085d90SJosh Poimboeuf * get these weak aliases and once-per-bootup warnings 248c624d33fSMasami Hiramatsu * (whenever this facility is utilized - for example by procfs): 2499212ddb5SIngo Molnar */ 2509212ddb5SIngo Molnar __weak void 2519212ddb5SIngo Molnar save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) 2529212ddb5SIngo Molnar { 2539212ddb5SIngo Molnar WARN_ONCE(1, KERN_INFO "save_stack_trace_tsk() not implemented yet.\n"); 2549212ddb5SIngo Molnar } 255c624d33fSMasami Hiramatsu 256c624d33fSMasami Hiramatsu __weak void 257c624d33fSMasami Hiramatsu save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) 258c624d33fSMasami Hiramatsu { 259c624d33fSMasami Hiramatsu WARN_ONCE(1, KERN_INFO "save_stack_trace_regs() not implemented yet.\n"); 260c624d33fSMasami Hiramatsu } 261af085d90SJosh Poimboeuf 262e9b98e16SThomas Gleixner /** 263e9b98e16SThomas Gleixner * stack_trace_save - Save a stack trace into a storage array 264e9b98e16SThomas Gleixner * @store: Pointer to storage array 265e9b98e16SThomas Gleixner * @size: Size of the storage array 266e9b98e16SThomas Gleixner * @skipnr: Number of entries to skip at the start of the stack trace 267e9b98e16SThomas Gleixner * 268e9b98e16SThomas Gleixner * Return: Number of trace entries stored 269e9b98e16SThomas Gleixner */ 270e9b98e16SThomas Gleixner unsigned int stack_trace_save(unsigned long *store, unsigned int size, 271e9b98e16SThomas Gleixner unsigned int skipnr) 272e9b98e16SThomas Gleixner { 273e9b98e16SThomas Gleixner struct stack_trace trace = { 274e9b98e16SThomas Gleixner .entries = store, 275e9b98e16SThomas Gleixner .max_entries = size, 276e9b98e16SThomas Gleixner .skip = skipnr + 1, 277e9b98e16SThomas Gleixner }; 278e9b98e16SThomas Gleixner 279e9b98e16SThomas Gleixner save_stack_trace(&trace); 280e9b98e16SThomas Gleixner return trace.nr_entries; 281e9b98e16SThomas Gleixner } 282e9b98e16SThomas Gleixner EXPORT_SYMBOL_GPL(stack_trace_save); 283e9b98e16SThomas Gleixner 284e9b98e16SThomas Gleixner /** 285e9b98e16SThomas Gleixner * stack_trace_save_tsk - Save a task stack trace into a storage array 286e9b98e16SThomas Gleixner * @task: The task to examine 287e9b98e16SThomas Gleixner * @store: Pointer to storage array 288e9b98e16SThomas Gleixner * @size: Size of the storage array 289e9b98e16SThomas Gleixner * @skipnr: Number of entries to skip at the start of the stack trace 290e9b98e16SThomas Gleixner * 291e9b98e16SThomas Gleixner * Return: Number of trace entries stored 292e9b98e16SThomas Gleixner */ 293e9b98e16SThomas Gleixner unsigned int stack_trace_save_tsk(struct task_struct *task, 294e9b98e16SThomas Gleixner unsigned long *store, unsigned int size, 295e9b98e16SThomas Gleixner unsigned int skipnr) 296e9b98e16SThomas Gleixner { 297e9b98e16SThomas Gleixner struct stack_trace trace = { 298e9b98e16SThomas Gleixner .entries = store, 299e9b98e16SThomas Gleixner .max_entries = size, 300b0c51f15SJiri Slaby /* skip this function if they are tracing us */ 3014b48512cSJiri Slaby .skip = skipnr + (current == task), 302e9b98e16SThomas Gleixner }; 303e9b98e16SThomas Gleixner 304e9b98e16SThomas Gleixner save_stack_trace_tsk(task, &trace); 305e9b98e16SThomas Gleixner return trace.nr_entries; 306e9b98e16SThomas Gleixner } 307e9b98e16SThomas Gleixner 308e9b98e16SThomas Gleixner /** 309e9b98e16SThomas Gleixner * stack_trace_save_regs - Save a stack trace based on pt_regs into a storage array 310e9b98e16SThomas Gleixner * @regs: Pointer to pt_regs to examine 311e9b98e16SThomas Gleixner * @store: Pointer to storage array 312e9b98e16SThomas Gleixner * @size: Size of the storage array 313e9b98e16SThomas Gleixner * @skipnr: Number of entries to skip at the start of the stack trace 314e9b98e16SThomas Gleixner * 315e9b98e16SThomas Gleixner * Return: Number of trace entries stored 316e9b98e16SThomas Gleixner */ 317e9b98e16SThomas Gleixner unsigned int stack_trace_save_regs(struct pt_regs *regs, unsigned long *store, 318e9b98e16SThomas Gleixner unsigned int size, unsigned int skipnr) 319e9b98e16SThomas Gleixner { 320e9b98e16SThomas Gleixner struct stack_trace trace = { 321e9b98e16SThomas Gleixner .entries = store, 322e9b98e16SThomas Gleixner .max_entries = size, 323e9b98e16SThomas Gleixner .skip = skipnr, 324e9b98e16SThomas Gleixner }; 325e9b98e16SThomas Gleixner 326e9b98e16SThomas Gleixner save_stack_trace_regs(regs, &trace); 327e9b98e16SThomas Gleixner return trace.nr_entries; 328e9b98e16SThomas Gleixner } 329e9b98e16SThomas Gleixner 330e9b98e16SThomas Gleixner #ifdef CONFIG_HAVE_RELIABLE_STACKTRACE 331e9b98e16SThomas Gleixner /** 332e9b98e16SThomas Gleixner * stack_trace_save_tsk_reliable - Save task stack with verification 333e9b98e16SThomas Gleixner * @tsk: Pointer to the task to examine 334e9b98e16SThomas Gleixner * @store: Pointer to storage array 335e9b98e16SThomas Gleixner * @size: Size of the storage array 336e9b98e16SThomas Gleixner * 337e9b98e16SThomas Gleixner * Return: An error if it detects any unreliable features of the 338e9b98e16SThomas Gleixner * stack. Otherwise it guarantees that the stack trace is 339e9b98e16SThomas Gleixner * reliable and returns the number of entries stored. 340e9b98e16SThomas Gleixner * 341e9b98e16SThomas Gleixner * If the task is not 'current', the caller *must* ensure the task is inactive. 342e9b98e16SThomas Gleixner */ 343e9b98e16SThomas Gleixner int stack_trace_save_tsk_reliable(struct task_struct *tsk, unsigned long *store, 344e9b98e16SThomas Gleixner unsigned int size) 345e9b98e16SThomas Gleixner { 346e9b98e16SThomas Gleixner struct stack_trace trace = { 347e9b98e16SThomas Gleixner .entries = store, 348e9b98e16SThomas Gleixner .max_entries = size, 349e9b98e16SThomas Gleixner }; 350e9b98e16SThomas Gleixner int ret = save_stack_trace_tsk_reliable(tsk, &trace); 351e9b98e16SThomas Gleixner 352e9b98e16SThomas Gleixner return ret ? ret : trace.nr_entries; 353e9b98e16SThomas Gleixner } 354e9b98e16SThomas Gleixner #endif 355e9b98e16SThomas Gleixner 356e9b98e16SThomas Gleixner #ifdef CONFIG_USER_STACKTRACE_SUPPORT 357e9b98e16SThomas Gleixner /** 358e9b98e16SThomas Gleixner * stack_trace_save_user - Save a user space stack trace into a storage array 359e9b98e16SThomas Gleixner * @store: Pointer to storage array 360e9b98e16SThomas Gleixner * @size: Size of the storage array 361e9b98e16SThomas Gleixner * 362e9b98e16SThomas Gleixner * Return: Number of trace entries stored 363e9b98e16SThomas Gleixner */ 364e9b98e16SThomas Gleixner unsigned int stack_trace_save_user(unsigned long *store, unsigned int size) 365e9b98e16SThomas Gleixner { 366e9b98e16SThomas Gleixner struct stack_trace trace = { 367e9b98e16SThomas Gleixner .entries = store, 368e9b98e16SThomas Gleixner .max_entries = size, 369e9b98e16SThomas Gleixner }; 370e9b98e16SThomas Gleixner 371e9b98e16SThomas Gleixner save_stack_trace_user(&trace); 372e9b98e16SThomas Gleixner return trace.nr_entries; 373e9b98e16SThomas Gleixner } 374e9b98e16SThomas Gleixner #endif /* CONFIG_USER_STACKTRACE_SUPPORT */ 375214d8ca6SThomas Gleixner 376214d8ca6SThomas Gleixner #endif /* !CONFIG_ARCH_STACKWALK */ 377*f39f21b3SMarco Elver 378*f39f21b3SMarco Elver static inline bool in_irqentry_text(unsigned long ptr) 379*f39f21b3SMarco Elver { 380*f39f21b3SMarco Elver return (ptr >= (unsigned long)&__irqentry_text_start && 381*f39f21b3SMarco Elver ptr < (unsigned long)&__irqentry_text_end) || 382*f39f21b3SMarco Elver (ptr >= (unsigned long)&__softirqentry_text_start && 383*f39f21b3SMarco Elver ptr < (unsigned long)&__softirqentry_text_end); 384*f39f21b3SMarco Elver } 385*f39f21b3SMarco Elver 386*f39f21b3SMarco Elver /** 387*f39f21b3SMarco Elver * filter_irq_stacks - Find first IRQ stack entry in trace 388*f39f21b3SMarco Elver * @entries: Pointer to stack trace array 389*f39f21b3SMarco Elver * @nr_entries: Number of entries in the storage array 390*f39f21b3SMarco Elver * 391*f39f21b3SMarco Elver * Return: Number of trace entries until IRQ stack starts. 392*f39f21b3SMarco Elver */ 393*f39f21b3SMarco Elver unsigned int filter_irq_stacks(unsigned long *entries, unsigned int nr_entries) 394*f39f21b3SMarco Elver { 395*f39f21b3SMarco Elver unsigned int i; 396*f39f21b3SMarco Elver 397*f39f21b3SMarco Elver for (i = 0; i < nr_entries; i++) { 398*f39f21b3SMarco Elver if (in_irqentry_text(entries[i])) { 399*f39f21b3SMarco Elver /* Include the irqentry function into the stack. */ 400*f39f21b3SMarco Elver return i + 1; 401*f39f21b3SMarco Elver } 402*f39f21b3SMarco Elver } 403*f39f21b3SMarco Elver return nr_entries; 404*f39f21b3SMarco Elver } 405*f39f21b3SMarco Elver EXPORT_SYMBOL_GPL(filter_irq_stacks); 406