blob: ca7591c51682e1fd71875ae42805f33871c36f2f [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2004 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38#include <vppinfra/clib.h>
39#include <vppinfra/error.h>
40
41#ifdef __mips__
42
43/* Let code below know we've defined _clib_backtrace */
44#define clib_backtrace_defined
45
46#include <vppinfra/asm_mips.h>
47
48uword
Dave Barachc3799992016-08-15 11:12:27 -040049clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip)
Ed Warnickecb9cada2015-12-08 15:45:58 -070050{
Dave Barachc3799992016-08-15 11:12:27 -040051 u32 *pc;
52 void *sp;
Ed Warnickecb9cada2015-12-08 15:45:58 -070053 uword i, saved_pc;
54
55 /* Figure current PC, saved PC and stack pointer. */
56 asm volatile (".set push\n"
Dave Barachc3799992016-08-15 11:12:27 -040057 ".set noat\n" "move %[saved_pc], $31\n" "move %[sp], $29\n"
Ed Warnickecb9cada2015-12-08 15:45:58 -070058 /* Fetches current PC. */
59 "la $at, 1f\n"
60 "jalr %[pc], $at\n"
61 "nop\n"
62 "1:\n"
Dave Barachc3799992016-08-15 11:12:27 -040063 ".set pop\n":[pc] "=r" (pc),
64 [saved_pc] "=r" (saved_pc),[sp] "=r" (sp));
Ed Warnickecb9cada2015-12-08 15:45:58 -070065
66 /* Also skip current frame. */
67 n_frames_to_skip += 1;
68
69 for (i = 0; i < max_callers + n_frames_to_skip; i++)
70 {
71 mips_insn_opcode_t op;
72 mips_insn_special_funct_t funct;
73 i32 insn, rs, rt, rd, immediate, found_saved_pc;
Dave Barachc3799992016-08-15 11:12:27 -040074 u32 *start_pc;
Ed Warnickecb9cada2015-12-08 15:45:58 -070075
76 /* Parse instructions until we reach prologue for this
Dave Barachc3799992016-08-15 11:12:27 -040077 stack frame. We'll need to figure out where saved
78 PC is and where previous stack frame lives. */
Ed Warnickecb9cada2015-12-08 15:45:58 -070079 start_pc = pc;
80 found_saved_pc = 0;
81 while (1)
82 {
83 insn = *--pc;
84 op = mips_insn_get_op (insn);
85 funct = mips_insn_get_funct (insn);
86 rs = mips_insn_get_rs (insn);
87 rt = mips_insn_get_rt (insn);
88 rd = mips_insn_get_rd (insn);
89 immediate = mips_insn_get_immediate (insn);
90
Dave Barachc3799992016-08-15 11:12:27 -040091 switch (op)
92 {
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 default:
Dave Barachc3799992016-08-15 11:12:27 -040094 break;
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
Dave Barachc3799992016-08-15 11:12:27 -040096 case MIPS_OPCODE_sd:
97 case MIPS_OPCODE_sw:
98 /* Trace stores of return address. */
99 if (rt == MIPS_REG_RA)
100 {
101 void *addr = sp + immediate;
102
103 /* If RA is stored somewhere other than in the
104 stack frame, give up. */
105 if (rs != MIPS_REG_SP)
106 goto backtrace_done;
107
108 ASSERT (immediate % 4 == 0);
109 if (op == MIPS_OPCODE_sw)
110 saved_pc = ((u32 *) addr)[0];
111 else
112 saved_pc = ((u64 *) addr)[0];
113 found_saved_pc = 1;
114 }
115 break;
116
117 case MIPS_OPCODE_addiu:
118 case MIPS_OPCODE_daddiu:
119 case MIPS_OPCODE_addi:
120 case MIPS_OPCODE_daddi:
121 if (rt == MIPS_REG_SP)
122 {
123 if (rs != MIPS_REG_SP)
124 goto backtrace_done;
125
126 ASSERT (immediate % 4 == 0);
127
128 /* Assume positive offset is part of the epilogue.
129 E.g.
130 jr ra
131 add sp,sp,100
132 */
133 if (immediate > 0)
134 continue;
135
136 /* Negative offset means allocate stack space.
137 This could either be the prologue or could be due to
138 alloca. */
139 sp -= immediate;
140
141 /* This frame will not save RA. */
142 if (i == 0)
143 goto found_prologue;
144
145 /* Assume that addiu sp,sp,-N without store of ra means
146 that we have not found the prologue yet. */
147 if (found_saved_pc)
148 goto found_prologue;
149 }
150 break;
151
152 case MIPS_OPCODE_slti:
153 case MIPS_OPCODE_sltiu:
154 case MIPS_OPCODE_andi:
155 case MIPS_OPCODE_ori:
156 case MIPS_OPCODE_xori:
157 case MIPS_OPCODE_lui:
158 case MIPS_OPCODE_ldl:
159 case MIPS_OPCODE_ldr:
160 case MIPS_OPCODE_lb:
161 case MIPS_OPCODE_lh:
162 case MIPS_OPCODE_lwl:
163 case MIPS_OPCODE_lw:
164 case MIPS_OPCODE_lbu:
165 case MIPS_OPCODE_lhu:
166 case MIPS_OPCODE_lwr:
167 case MIPS_OPCODE_lwu:
168 case MIPS_OPCODE_ld:
169 /* Give up when we find anyone setting the stack pointer. */
170 if (rt == MIPS_REG_SP)
171 goto backtrace_done;
172 break;
173
174 case MIPS_OPCODE_SPECIAL:
175 if (rd == MIPS_REG_SP)
176 switch (funct)
177 {
178 default:
179 /* Give up when we find anyone setting the stack pointer. */
180 goto backtrace_done;
181
182 case MIPS_SPECIAL_FUNCT_break:
183 case MIPS_SPECIAL_FUNCT_jr:
184 case MIPS_SPECIAL_FUNCT_sync:
185 case MIPS_SPECIAL_FUNCT_syscall:
186 case MIPS_SPECIAL_FUNCT_tge:
187 case MIPS_SPECIAL_FUNCT_tgeu:
188 case MIPS_SPECIAL_FUNCT_tlt:
189 case MIPS_SPECIAL_FUNCT_tltu:
190 case MIPS_SPECIAL_FUNCT_teq:
191 case MIPS_SPECIAL_FUNCT_tne:
192 /* These instructions can validly have rd == MIPS_REG_SP */
193 break;
194 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 break;
196 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 }
198
199 found_prologue:
200 /* Check sanity of saved pc. */
201 if (saved_pc & 3)
Dave Barachc3799992016-08-15 11:12:27 -0400202 goto backtrace_done;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203 if (saved_pc == 0)
Dave Barachc3799992016-08-15 11:12:27 -0400204 goto backtrace_done;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205
206 if (i >= n_frames_to_skip)
207 callers[i - n_frames_to_skip] = saved_pc;
208 pc = uword_to_pointer (saved_pc, u32 *);
209 }
210
Dave Barachc3799992016-08-15 11:12:27 -0400211backtrace_done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700212 if (i < n_frames_to_skip)
213 return 0;
214 else
215 return i - n_frames_to_skip;
216}
217#endif /* __mips__ */
218
219#ifndef clib_backtrace_defined
220#define clib_backtrace_defined
221
Kingwel Xie497deaf2018-06-15 04:56:24 -0400222/* use glibc backtrace for stack trace */
223#include <execinfo.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -0700224
Ed Warnickecb9cada2015-12-08 15:45:58 -0700225uword
Dave Barachc3799992016-08-15 11:12:27 -0400226clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700227{
Kingwel Xie497deaf2018-06-15 04:56:24 -0400228 int size;
229 void *array[20];
Ed Warnickecb9cada2015-12-08 15:45:58 -0700230 /* Also skip current frame. */
231 n_frames_to_skip += 1;
232
Kingwel Xie497deaf2018-06-15 04:56:24 -0400233 size = clib_min (ARRAY_LEN (array), max_callers + n_frames_to_skip);
234
235 size = backtrace (array, size);
236
237 uword i;
238
239 for (i = 0; i < max_callers + n_frames_to_skip && i < size; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240 {
Ed Warnickecb9cada2015-12-08 15:45:58 -0700241 if (i >= n_frames_to_skip)
Kingwel Xie497deaf2018-06-15 04:56:24 -0400242 callers[i - n_frames_to_skip] = pointer_to_uword (array[i]);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700243 }
244
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 if (i < n_frames_to_skip)
Dave Barachc3799992016-08-15 11:12:27 -0400246 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247 else
Dave Barachc3799992016-08-15 11:12:27 -0400248 return i - n_frames_to_skip;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700249}
Kingwel Xie497deaf2018-06-15 04:56:24 -0400250
251
Ed Warnickecb9cada2015-12-08 15:45:58 -0700252#endif /* clib_backtrace_defined */
Dave Barachc3799992016-08-15 11:12:27 -0400253
254/*
255 * fd.io coding-style-patch-verification: ON
256 *
257 * Local Variables:
258 * eval: (c-set-style "gnu")
259 * End:
260 */