static int __save_stack_trace_reliable(struct stack_trace *trace, struct task_struct *task) { struct unwind_state state; struct pt_regs *regs; unsigned long addr; for (unwind_start(&state, task, NULL, NULL); !unwind_done(&state); unwind_next_frame(&state)) { regs = unwind_get_entry_regs(&state); if (regs) { /* * Kernel mode registers on the stack indicate an * in-kernel interrupt or exception (e.g., preemption * or a page fault), which can make frame pointers * unreliable. */ if (!user_mode(regs)) return -EINVAL; /* * The last frame contains the user mode syscall * pt_regs. Skip it and finish the unwind. */ unwind_next_frame(&state); if (!unwind_done(&state)) { STACKTRACE_DUMP_ONCE(task); return -EINVAL; } break; } addr = unwind_get_return_address(&state); /* * A NULL or invalid return address probably means there's some * generated code which __kernel_text_address() doesn't know * about. */ if (!addr) { STACKTRACE_DUMP_ONCE(task); return -EINVAL; } if (save_stack_address(trace, addr, false)) return -EINVAL; } /* Check for stack corruption */ if (unwind_error(&state)) { STACKTRACE_DUMP_ONCE(task); return -EINVAL; } if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; return 0; }
static void __save_stack_trace(struct stack_trace *trace, struct task_struct *task, struct pt_regs *regs, bool nosched) { struct unwind_state state; unsigned long addr; if (regs) save_stack_address(trace, regs->ip, nosched); for (unwind_start(&state, task, regs, NULL); !unwind_done(&state); unwind_next_frame(&state)) { addr = unwind_get_return_address(&state); if (!addr || save_stack_address(trace, addr, nosched)) break; } if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; }
void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, char *log_lvl) { struct unwind_state state; struct stack_info stack_info = {0}; unsigned long visit_mask = 0; int graph_idx = 0; printk("%sCall Trace:\n", log_lvl); unwind_start(&state, task, regs, stack); stack = stack ? : get_stack_pointer(task, regs); /* * Iterate through the stacks, starting with the current stack pointer. * Each stack has a pointer to the next one. * * x86-64 can have several stacks: * - task stack * - interrupt stack * - HW exception stacks (double fault, nmi, debug, mce) * * x86-32 can have up to three stacks: * - task stack * - softirq stack * - hardirq stack */ for (regs = NULL; stack; stack = stack_info.next_sp) { const char *stack_name; /* * If we overflowed the task stack into a guard page, jump back * to the bottom of the usable stack. */ if (task_stack_page(task) - (void *)stack < PAGE_SIZE) stack = task_stack_page(task); if (get_stack_info(stack, task, &stack_info, &visit_mask)) break; stack_name = stack_type_name(stack_info.type); if (stack_name) printk("%s <%s>\n", log_lvl, stack_name); /* * Scan the stack, printing any text addresses we find. At the * same time, follow proper stack frames with the unwinder. * * Addresses found during the scan which are not reported by * the unwinder are considered to be additional clues which are * sometimes useful for debugging and are prefixed with '?'. * This also serves as a failsafe option in case the unwinder * goes off in the weeds. */ for (; stack < stack_info.end; stack++) { unsigned long real_addr; int reliable = 0; unsigned long addr = READ_ONCE_NOCHECK(*stack); unsigned long *ret_addr_p = unwind_get_return_address_ptr(&state); if (!__kernel_text_address(addr)) continue; /* * Don't print regs->ip again if it was already printed * by __show_regs() below. */ if (regs && stack == ®s->ip) { unwind_next_frame(&state); continue; } if (stack == ret_addr_p) reliable = 1; /* * When function graph tracing is enabled for a * function, its return address on the stack is * replaced with the address of an ftrace handler * (return_to_handler). In that case, before printing * the "real" address, we want to print the handler * address as an "unreliable" hint that function graph * tracing was involved. */ real_addr = ftrace_graph_ret_addr(task, &graph_idx, addr, stack); if (real_addr != addr) printk_stack_address(addr, 0, log_lvl); printk_stack_address(real_addr, reliable, log_lvl); if (!reliable) continue; /* * Get the next frame from the unwinder. No need to * check for an error: if anything goes wrong, the rest * of the addresses will just be printed as unreliable. */ unwind_next_frame(&state); /* if the frame has entry regs, print them */ regs = unwind_get_entry_regs(&state); if (regs) __show_regs(regs, 0); } if (stack_name) printk("%s </%s>\n", log_lvl, stack_name); } }