Line data Source code
1 : /*
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 :
48 : __clib_export uword
49 : clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip)
50 : {
51 : u32 *pc;
52 : void *sp;
53 : uword i, saved_pc;
54 :
55 : /* Figure current PC, saved PC and stack pointer. */
56 : asm volatile (".set push\n"
57 : ".set noat\n" "move %[saved_pc], $31\n" "move %[sp], $29\n"
58 : /* Fetches current PC. */
59 : "la $at, 1f\n"
60 : "jalr %[pc], $at\n"
61 : "nop\n"
62 : "1:\n"
63 : ".set pop\n":[pc] "=r" (pc),
64 : [saved_pc] "=r" (saved_pc),[sp] "=r" (sp));
65 :
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;
74 : u32 *start_pc;
75 :
76 : /* Parse instructions until we reach prologue for this
77 : stack frame. We'll need to figure out where saved
78 : PC is and where previous stack frame lives. */
79 : 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 :
91 : switch (op)
92 : {
93 : default:
94 : break;
95 :
96 : 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 : }
195 : break;
196 : }
197 : }
198 :
199 : found_prologue:
200 : /* Check sanity of saved pc. */
201 : if (saved_pc & 3)
202 : goto backtrace_done;
203 : if (saved_pc == 0)
204 : goto backtrace_done;
205 :
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 :
211 : backtrace_done:
212 : 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 :
222 : /* use glibc backtrace for stack trace */
223 : #include <execinfo.h>
224 :
225 : __clib_export uword
226 22 : clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip)
227 : {
228 : int size;
229 : void *array[20];
230 : /* Also skip current frame. */
231 22 : n_frames_to_skip += 1;
232 :
233 22 : size = clib_min (ARRAY_LEN (array), max_callers + n_frames_to_skip);
234 :
235 22 : size = backtrace (array, size);
236 :
237 : uword i;
238 :
239 348 : for (i = 0; i < max_callers + n_frames_to_skip && i < size; i++)
240 : {
241 326 : if (i >= n_frames_to_skip)
242 520 : callers[i - n_frames_to_skip] = pointer_to_uword (array[i]);
243 : }
244 :
245 22 : if (i < n_frames_to_skip)
246 0 : return 0;
247 : else
248 22 : return i - n_frames_to_skip;
249 : }
250 :
251 :
252 : #endif /* clib_backtrace_defined */
253 :
254 : /*
255 : * fd.io coding-style-patch-verification: ON
256 : *
257 : * Local Variables:
258 : * eval: (c-set-style "gnu")
259 : * End:
260 : */
|