cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

stacktrace.c (2358B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Stack trace management functions
      4 *
      5 *  Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
      6 */
      7#include <linux/sched.h>
      8#include <linux/sched/debug.h>
      9#include <linux/sched/task_stack.h>
     10#include <linux/stacktrace.h>
     11#include <linux/export.h>
     12#include <asm/stacktrace.h>
     13
     14/*
     15 * Save stack-backtrace addresses into a stack_trace buffer:
     16 */
     17static void save_raw_context_stack(struct stack_trace *trace,
     18	unsigned long reg29, int savesched)
     19{
     20	unsigned long *sp = (unsigned long *)reg29;
     21	unsigned long addr;
     22
     23	while (!kstack_end(sp)) {
     24		addr = *sp++;
     25		if (__kernel_text_address(addr) &&
     26		    (savesched || !in_sched_functions(addr))) {
     27			if (trace->skip > 0)
     28				trace->skip--;
     29			else
     30				trace->entries[trace->nr_entries++] = addr;
     31			if (trace->nr_entries >= trace->max_entries)
     32				break;
     33		}
     34	}
     35}
     36
     37static void save_context_stack(struct stack_trace *trace,
     38	struct task_struct *tsk, struct pt_regs *regs, int savesched)
     39{
     40	unsigned long sp = regs->regs[29];
     41#ifdef CONFIG_KALLSYMS
     42	unsigned long ra = regs->regs[31];
     43	unsigned long pc = regs->cp0_epc;
     44
     45	if (raw_show_trace || !__kernel_text_address(pc)) {
     46		unsigned long stack_page =
     47			(unsigned long)task_stack_page(tsk);
     48		if (stack_page && sp >= stack_page &&
     49		    sp <= stack_page + THREAD_SIZE - 32)
     50			save_raw_context_stack(trace, sp, savesched);
     51		return;
     52	}
     53	do {
     54		if (savesched || !in_sched_functions(pc)) {
     55			if (trace->skip > 0)
     56				trace->skip--;
     57			else
     58				trace->entries[trace->nr_entries++] = pc;
     59			if (trace->nr_entries >= trace->max_entries)
     60				break;
     61		}
     62		pc = unwind_stack(tsk, &sp, pc, &ra);
     63	} while (pc);
     64#else
     65	save_raw_context_stack(trace, sp, savesched);
     66#endif
     67}
     68
     69/*
     70 * Save stack-backtrace addresses into a stack_trace buffer.
     71 */
     72void save_stack_trace(struct stack_trace *trace)
     73{
     74	save_stack_trace_tsk(current, trace);
     75}
     76EXPORT_SYMBOL_GPL(save_stack_trace);
     77
     78void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
     79{
     80	struct pt_regs dummyregs;
     81	struct pt_regs *regs = &dummyregs;
     82
     83	WARN_ON(trace->nr_entries || !trace->max_entries);
     84
     85	if (tsk != current) {
     86		regs->regs[29] = tsk->thread.reg29;
     87		regs->regs[31] = 0;
     88		regs->cp0_epc = tsk->thread.reg31;
     89	} else
     90		prepare_frametrace(regs);
     91	save_context_stack(trace, tsk, regs, tsk == current);
     92}
     93EXPORT_SYMBOL_GPL(save_stack_trace_tsk);