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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
/** @file
RISC-V backtrace implementation.
Copyright (c) 2016 - 2022, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Backtrace.h"
#define MAX_STACK_FRAME_SIZE SIZE_16KB
STATIC
INTN
CheckFpValid (
IN UINTN Fp,
IN UINTN Sp
)
{
UINTN Low, High;
Low = Sp + 2 * sizeof (UINTN);
High = ALIGN_VALUE (Sp, MAX_STACK_FRAME_SIZE);
return !(Fp < Low || Fp > High || Fp & 0x07);
}
STATIC
CONST CHAR8 *
BaseName (
IN CONST CHAR8 *FullName
)
{
CONST CHAR8 *Str;
Str = FullName + AsciiStrLen (FullName);
while (--Str > FullName) {
if ((*Str == '/') || (*Str == '\\')) {
return Str + 1;
}
}
return Str;
}
/**
Helper for displaying a backtrace.
@param Regs Pointer to SMODE_TRAP_REGISTERS.
@param FirstPdb Pointer to the first symbol file used.
@param ListImage If true, only show the full path to symbol file, else
show the PC value and its decoded components.
**/
STATIC
VOID
DumpCpuBacktraceHelper (
IN SMODE_TRAP_REGISTERS *Regs,
IN CHAR8 *FirstPdb,
IN BOOLEAN ListImage
)
{
UINTN ImageBase;
UINTN PeCoffSizeOfHeader;
BOOLEAN IsLeaf;
UINTN RootFp;
UINTN RootRa;
UINTN Sp;
UINTN Fp;
UINTN Ra;
UINTN Idx;
CHAR8 *Pdb;
CHAR8 *PrevPdb;
RootRa = Regs->ra;
RootFp = Regs->s0;
Idx = 0;
IsLeaf = TRUE;
Fp = RootFp;
Ra = RootRa;
PrevPdb = FirstPdb;
while (Fp != 0) {
Pdb = GetImageName (Ra, &ImageBase, &PeCoffSizeOfHeader);
if (Pdb != NULL) {
if (Pdb != PrevPdb) {
Idx++;
if (ListImage) {
DEBUG ((DEBUG_ERROR, "[% 2d] %a\n", Idx, Pdb));
}
PrevPdb = Pdb;
}
if (!ListImage) {
DEBUG ((
DEBUG_ERROR,
"PC 0x%012lx (0x%012lx+0x%08x) [% 2d] %a\n",
Ra,
ImageBase,
Ra - ImageBase,
Idx,
BaseName (Pdb)
));
}
} else if (!ListImage) {
DEBUG ((DEBUG_ERROR, "PC 0x%012lx\n", Ra));
}
/*
* After the prologue, the frame pointer register s0 will point
* to the Canonical Frame Address or CFA, which is the stack
* pointer value on entry to the current procedure. The previous
* frame pointer and return address pair will reside just prior
* to the current stack address held in s0. This puts the return
* address at s0 - XLEN/8, and the previous frame pointer at
* s0 - 2 * XLEN/8.
*/
Sp = Fp;
Fp -= sizeof (UINTN) * 2;
Ra = *(UINTN *)(Fp + sizeof (UINTN));
Fp = *(UINTN *)(Fp);
if (IsLeaf && CheckFpValid (Ra, Sp)) {
/* We hit function where ra is not saved on the stack */
Fp = Ra;
Ra = RootRa;
}
IsLeaf = FALSE;
}
}
/**
Display a backtrace.
@param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
**/
VOID
EFIAPI
DumpCpuBacktrace (
IN EFI_SYSTEM_CONTEXT SystemContext
)
{
SMODE_TRAP_REGISTERS *Regs;
CHAR8 *Pdb;
UINTN ImageBase;
UINTN PeCoffSizeOfHeader;
Regs = (SMODE_TRAP_REGISTERS *)SystemContext.SystemContextRiscV64;
Pdb = GetImageName (Regs->sepc, &ImageBase, &PeCoffSizeOfHeader);
if (Pdb != NULL) {
DEBUG ((
DEBUG_ERROR,
"PC 0x%012lx (0x%012lx+0x%08x) [ 0] %a\n",
Regs->sepc,
ImageBase,
Regs->sepc - ImageBase,
BaseName (Pdb)
));
} else {
DEBUG ((DEBUG_ERROR, "PC 0x%012lx\n", Regs->sepc));
}
DumpCpuBacktraceHelper (Regs, Pdb, FALSE);
if (Pdb != NULL) {
DEBUG ((DEBUG_ERROR, "\n[ 0] %a\n", Pdb));
}
DumpCpuBacktraceHelper (Regs, Pdb, TRUE);
}
|