18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2009  Matt Fleming
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Based, in part, on kernel/time/clocksource.c.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This file provides arbitration code for stack unwinders.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Multiple stack unwinders can be available on a system, usually with
108c2ecf20Sopenharmony_ci * the most accurate unwinder being the currently active one.
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#include <linux/errno.h>
138c2ecf20Sopenharmony_ci#include <linux/list.h>
148c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <asm/unwinder.h>
178c2ecf20Sopenharmony_ci#include <linux/atomic.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * This is the most basic stack unwinder an architecture can
218c2ecf20Sopenharmony_ci * provide. For architectures without reliable frame pointers, e.g.
228c2ecf20Sopenharmony_ci * RISC CPUs, it can be implemented by looking through the stack for
238c2ecf20Sopenharmony_ci * addresses that lie within the kernel text section.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * Other CPUs, e.g. x86, can use their frame pointer register to
268c2ecf20Sopenharmony_ci * construct more accurate stack traces.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_cistatic struct list_head unwinder_list;
298c2ecf20Sopenharmony_cistatic struct unwinder stack_reader = {
308c2ecf20Sopenharmony_ci	.name = "stack-reader",
318c2ecf20Sopenharmony_ci	.dump = stack_reader_dump,
328c2ecf20Sopenharmony_ci	.rating = 50,
338c2ecf20Sopenharmony_ci	.list = {
348c2ecf20Sopenharmony_ci		.next = &unwinder_list,
358c2ecf20Sopenharmony_ci		.prev = &unwinder_list,
368c2ecf20Sopenharmony_ci	},
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * "curr_unwinder" points to the stack unwinder currently in use. This
418c2ecf20Sopenharmony_ci * is the unwinder with the highest rating.
428c2ecf20Sopenharmony_ci *
438c2ecf20Sopenharmony_ci * "unwinder_list" is a linked-list of all available unwinders, sorted
448c2ecf20Sopenharmony_ci * by rating.
458c2ecf20Sopenharmony_ci *
468c2ecf20Sopenharmony_ci * All modifications of "curr_unwinder" and "unwinder_list" must be
478c2ecf20Sopenharmony_ci * performed whilst holding "unwinder_lock".
488c2ecf20Sopenharmony_ci */
498c2ecf20Sopenharmony_cistatic struct unwinder *curr_unwinder = &stack_reader;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic struct list_head unwinder_list = {
528c2ecf20Sopenharmony_ci	.next = &stack_reader.list,
538c2ecf20Sopenharmony_ci	.prev = &stack_reader.list,
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(unwinder_lock);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/**
598c2ecf20Sopenharmony_ci * select_unwinder - Select the best registered stack unwinder.
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * Private function. Must hold unwinder_lock when called.
628c2ecf20Sopenharmony_ci *
638c2ecf20Sopenharmony_ci * Select the stack unwinder with the best rating. This is useful for
648c2ecf20Sopenharmony_ci * setting up curr_unwinder.
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_cistatic struct unwinder *select_unwinder(void)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	struct unwinder *best;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (list_empty(&unwinder_list))
718c2ecf20Sopenharmony_ci		return NULL;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	best = list_entry(unwinder_list.next, struct unwinder, list);
748c2ecf20Sopenharmony_ci	if (best == curr_unwinder)
758c2ecf20Sopenharmony_ci		return NULL;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return best;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/*
818c2ecf20Sopenharmony_ci * Enqueue the stack unwinder sorted by rating.
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_cistatic int unwinder_enqueue(struct unwinder *ops)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct list_head *tmp, *entry = &unwinder_list;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	list_for_each(tmp, &unwinder_list) {
888c2ecf20Sopenharmony_ci		struct unwinder *o;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		o = list_entry(tmp, struct unwinder, list);
918c2ecf20Sopenharmony_ci		if (o == ops)
928c2ecf20Sopenharmony_ci			return -EBUSY;
938c2ecf20Sopenharmony_ci		/* Keep track of the place, where to insert */
948c2ecf20Sopenharmony_ci		if (o->rating >= ops->rating)
958c2ecf20Sopenharmony_ci			entry = tmp;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci	list_add(&ops->list, entry);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	return 0;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/**
1038c2ecf20Sopenharmony_ci * unwinder_register - Used to install new stack unwinder
1048c2ecf20Sopenharmony_ci * @u: unwinder to be registered
1058c2ecf20Sopenharmony_ci *
1068c2ecf20Sopenharmony_ci * Install the new stack unwinder on the unwinder list, which is sorted
1078c2ecf20Sopenharmony_ci * by rating.
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci * Returns -EBUSY if registration fails, zero otherwise.
1108c2ecf20Sopenharmony_ci */
1118c2ecf20Sopenharmony_ciint unwinder_register(struct unwinder *u)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	unsigned long flags;
1148c2ecf20Sopenharmony_ci	int ret;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&unwinder_lock, flags);
1178c2ecf20Sopenharmony_ci	ret = unwinder_enqueue(u);
1188c2ecf20Sopenharmony_ci	if (!ret)
1198c2ecf20Sopenharmony_ci		curr_unwinder = select_unwinder();
1208c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&unwinder_lock, flags);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return ret;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ciint unwinder_faulted = 0;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci/*
1288c2ecf20Sopenharmony_ci * Unwind the call stack and pass information to the stacktrace_ops
1298c2ecf20Sopenharmony_ci * functions. Also handle the case where we need to switch to a new
1308c2ecf20Sopenharmony_ci * stack dumper because the current one faulted unexpectedly.
1318c2ecf20Sopenharmony_ci */
1328c2ecf20Sopenharmony_civoid unwind_stack(struct task_struct *task, struct pt_regs *regs,
1338c2ecf20Sopenharmony_ci		  unsigned long *sp, const struct stacktrace_ops *ops,
1348c2ecf20Sopenharmony_ci		  void *data)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	unsigned long flags;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/*
1398c2ecf20Sopenharmony_ci	 * The problem with unwinders with high ratings is that they are
1408c2ecf20Sopenharmony_ci	 * inherently more complicated than the simple ones with lower
1418c2ecf20Sopenharmony_ci	 * ratings. We are therefore more likely to fault in the
1428c2ecf20Sopenharmony_ci	 * complicated ones, e.g. hitting BUG()s. If we fault in the
1438c2ecf20Sopenharmony_ci	 * code for the current stack unwinder we try to downgrade to
1448c2ecf20Sopenharmony_ci	 * one with a lower rating.
1458c2ecf20Sopenharmony_ci	 *
1468c2ecf20Sopenharmony_ci	 * Hopefully this will give us a semi-reliable stacktrace so we
1478c2ecf20Sopenharmony_ci	 * can diagnose why curr_unwinder->dump() faulted.
1488c2ecf20Sopenharmony_ci	 */
1498c2ecf20Sopenharmony_ci	if (unwinder_faulted) {
1508c2ecf20Sopenharmony_ci		spin_lock_irqsave(&unwinder_lock, flags);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		/* Make sure no one beat us to changing the unwinder */
1538c2ecf20Sopenharmony_ci		if (unwinder_faulted && !list_is_singular(&unwinder_list)) {
1548c2ecf20Sopenharmony_ci			list_del(&curr_unwinder->list);
1558c2ecf20Sopenharmony_ci			curr_unwinder = select_unwinder();
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci			unwinder_faulted = 0;
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&unwinder_lock, flags);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	curr_unwinder->dump(task, regs, sp, ops, data);
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unwind_stack);
166