hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
 * OpenRISC unwinder.c
 *
 * Reusable arch specific api for unwinding stacks.
 *
 * Copyright (C) 2017 Stafford Horne <shorne@gmail.com>
 *
 * This file is licensed under the terms of the GNU General Public License
 * version 2.  This program is licensed "as is" without any warranty of any
 * kind, whether express or implied.
 */
 
#include <linux/sched/task_stack.h>
#include <linux/kernel.h>
 
#include <asm/unwinder.h>
 
#ifdef CONFIG_FRAME_POINTER
struct or1k_frameinfo {
   unsigned long *fp;
   unsigned long ra;
   unsigned long top;
};
 
/*
 * Verify a frameinfo structure.  The return address should be a valid text
 * address.  The frame pointer may be null if its the last frame, otherwise
 * the frame pointer should point to a location in the stack after the the
 * top of the next frame up.
 */
static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
{
   return (frameinfo->fp == NULL ||
       (!kstack_end(frameinfo->fp) &&
        frameinfo->fp > &frameinfo->top)) &&
          __kernel_text_address(frameinfo->ra);
}
 
/*
 * Create a stack trace doing scanning which is frame pointer aware. We can
 * get reliable stack traces by matching the previously found frame
 * pointer with the top of the stack address every time we find a valid
 * or1k_frameinfo.
 *
 * Ideally the stack parameter will be passed as FP, but it can not be
 * guaranteed.  Therefore we scan each address looking for the first sign
 * of a return address.
 *
 * The OpenRISC stack frame looks something like the following.  The
 * location SP is held in r1 and location FP is held in r2 when frame pointers
 * enabled.
 *
 * SP   -> (top of stack)
 *      -  (callee saved registers)
 *      -  (local variables)
 * FP-8 -> previous FP             \
 * FP-4 -> return address          |- or1k_frameinfo
 * FP   -> (previous top of stack) /
 */
void unwind_stack(void *data, unsigned long *stack,
         void (*trace)(void *data, unsigned long addr, int reliable))
{
   unsigned long *next_fp = NULL;
   struct or1k_frameinfo *frameinfo = NULL;
   int reliable = 0;
 
   while (!kstack_end(stack)) {
       frameinfo = container_of(stack,
                    struct or1k_frameinfo,
                    top);
 
       if (__kernel_text_address(frameinfo->ra)) {
           if (or1k_frameinfo_valid(frameinfo) &&
               (next_fp == NULL ||
                next_fp == &frameinfo->top)) {
               reliable = 1;
               next_fp = frameinfo->fp;
           } else
               reliable = 0;
 
           trace(data, frameinfo->ra, reliable);
       }
       stack++;
   }
}
 
#else /* CONFIG_FRAME_POINTER */
 
/*
 * Create a stack trace by doing a simple scan treating all text addresses
 * as return addresses.
 */
void unwind_stack(void *data, unsigned long *stack,
          void (*trace)(void *data, unsigned long addr, int reliable))
{
   unsigned long addr;
 
   while (!kstack_end(stack)) {
       addr = *stack++;
       if (__kernel_text_address(addr))
           trace(data, addr, 0);
   }
}
#endif /* CONFIG_FRAME_POINTER */