Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc850d6b authored by Arjan van de Ven's avatar Arjan van de Ven Committed by Ingo Molnar
Browse files

x86: add the capability to print fuzzy backtraces



For enhancing the 32 bit EBP based backtracer, I need the capability
for the backtracer to tell it's customer that an entry is either
reliable or unreliable, and the backtrace printing code then needs to
print the unreliable ones slightly different.

This patch adds the basic capability, the next patch will add a user
of this capability.

Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 3d1f7cae
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ static void dump_leak(void)
	       iommu_leak_pages);
	for (i = 0; i < iommu_leak_pages; i += 2) {
		printk(KERN_DEBUG "%lu: ", iommu_pages-i);
		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i]);
		printk_address((unsigned long) iommu_leak_tab[iommu_pages-i], 0);
		printk(KERN_CONT "%c", (i+1)%2 == 0 ? '\n' : ' ');
	}
	printk(KERN_DEBUG "\n");
+2 −2
Original line number Diff line number Diff line
@@ -329,7 +329,7 @@ void __show_regs(struct pt_regs * regs)
		(int)strcspn(init_utsname()->version, " "),
		init_utsname()->version);
	printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->ip);
	printk_address(regs->ip);
	printk_address(regs->ip, regs->bp);
	printk("RSP: %04lx:%016lx  EFLAGS: %08lx\n", regs->ss, regs->sp,
		regs->flags);
	printk("RAX: %016lx RBX: %016lx RCX: %016lx\n",
@@ -377,7 +377,7 @@ void show_regs(struct pt_regs *regs)
{
	printk("CPU %d:", smp_processor_id());
	__show_regs(regs);
	show_trace(NULL, regs, (void *)(regs + 1));
	show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
}

/*
+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ static int save_stack_stack(void *data, char *name)
	return -1;
}

static void save_stack_address(void *data, unsigned long addr)
static void save_stack_address(void *data, unsigned long addr, int reliable)
{
	struct stack_trace *trace = (struct stack_trace *)data;
	if (trace->skip > 0) {
+5 −3
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,

		addr = frame->return_address;
		if (__kernel_text_address(addr))
			ops->address(data, addr);
			ops->address(data, addr, 1);
		/*
		 * break out of recursive entries (such as
		 * end_of_stack_stop_unwind_function). Also,
@@ -145,7 +145,7 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,

		addr = *stack++;
		if (__kernel_text_address(addr))
			ops->address(data, addr);
			ops->address(data, addr, 1);
	}
#endif
	return bp;
@@ -220,9 +220,11 @@ static int print_trace_stack(void *data, char *name)
/*
 * Print one address/symbol entries per line.
 */
static void print_trace_address(void *data, unsigned long addr)
static void print_trace_address(void *data, unsigned long addr, int reliable)
{
	printk("%s [<%08lx>] ", (char *)data, addr);
	if (!reliable)
		printk("? ");
	print_symbol("%s\n", addr);
	touch_nmi_watchdog();
}
+23 −16
Original line number Diff line number Diff line
@@ -99,13 +99,14 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
int kstack_depth_to_print = 12;

#ifdef CONFIG_KALLSYMS
void printk_address(unsigned long address)
void printk_address(unsigned long address, int reliable)
{
	unsigned long offset = 0, symsize;
	const char *symname;
	char *modname;
	char *delim = ":";
	char namebuf[128];
	char reliab[4] = "";;

	symname = kallsyms_lookup(address, &symsize, &offset,
					&modname, namebuf);
@@ -113,13 +114,16 @@ void printk_address(unsigned long address)
		printk(" [<%016lx>]\n", address);
		return;
	}
	if (!reliable)
		strcpy(reliab, "? ");

	if (!modname)
		modname = delim = ""; 		
	printk(" [<%016lx>] %s%s%s%s+0x%lx/0x%lx\n",
		address, delim, modname, delim, symname, offset, symsize);
	printk(" [<%016lx>] %s%s%s%s%s+0x%lx/0x%lx\n",
		address, reliab, delim, modname, delim, symname, offset, symsize);
}
#else
void printk_address(unsigned long address)
void printk_address(unsigned long address, int reliable)
{
	printk(" [<%016lx>]\n", address);
}
@@ -215,7 +219,7 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
}

void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
		unsigned long *stack,
		unsigned long *stack, unsigned long bp,
		const struct stacktrace_ops *ops, void *data)
{
	const unsigned cpu = get_cpu();
@@ -252,7 +256,7 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
			 * down the cause of the crash will be able to figure \
			 * out the call path that was taken. \
			 */ \
			ops->address(data, addr);   \
			ops->address(data, addr, 1);   \
		} \
	} while (0)

@@ -331,10 +335,10 @@ static int print_trace_stack(void *data, char *name)
	return 0;
}

static void print_trace_address(void *data, unsigned long addr)
static void print_trace_address(void *data, unsigned long addr, int reliable)
{
	touch_nmi_watchdog();
	printk_address(addr);
	printk_address(addr, reliable);
}

static const struct stacktrace_ops print_trace_ops = {
@@ -345,15 +349,17 @@ static const struct stacktrace_ops print_trace_ops = {
};

void
show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack)
show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack,
		unsigned long bp)
{
	printk("\nCall Trace:\n");
	dump_trace(tsk, regs, stack, &print_trace_ops, NULL);
	dump_trace(tsk, regs, stack, bp, &print_trace_ops, NULL);
	printk("\n");
}

static void
_show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp)
_show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp,
							unsigned long bp)
{
	unsigned long *stack;
	int i;
@@ -387,12 +393,12 @@ _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *sp)
		printk(" %016lx", *stack++);
		touch_nmi_watchdog();
	}
	show_trace(tsk, regs, sp);
	show_trace(tsk, regs, sp, bp);
}

void show_stack(struct task_struct *tsk, unsigned long * sp)
{
	_show_stack(tsk, NULL, sp);
	_show_stack(tsk, NULL, sp, 0);
}

/*
@@ -401,13 +407,14 @@ void show_stack(struct task_struct *tsk, unsigned long * sp)
void dump_stack(void)
{
	unsigned long dummy;
	unsigned long bp = 0;

	printk("Pid: %d, comm: %.20s %s %s %.*s\n",
		current->pid, current->comm, print_tainted(),
		init_utsname()->release,
		(int)strcspn(init_utsname()->version, " "),
		init_utsname()->version);
	show_trace(NULL, NULL, &dummy);
	show_trace(NULL, NULL, &dummy, bp);
}

EXPORT_SYMBOL(dump_stack);
@@ -432,7 +439,7 @@ void show_registers(struct pt_regs *regs)
	 */
	if (in_kernel) {
		printk("Stack: ");
		_show_stack(NULL, regs, (unsigned long*)sp);
		_show_stack(NULL, regs, (unsigned long *)sp, regs->bp);

		printk("\nCode: ");
		if (regs->ip < PAGE_OFFSET)
@@ -527,7 +534,7 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err)
	add_taint(TAINT_DIE);
	/* Executive summary in case the oops scrolled away */
	printk(KERN_ALERT "RIP ");
	printk_address(regs->ip);
	printk_address(regs->ip, regs->bp);
	printk(" RSP <%016lx>\n", regs->sp);
	if (kexec_should_crash(current))
		crash_kexec(regs);
Loading