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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 Copyright (c) 2004 Eliot Dresselhaus
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:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
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.
38 #include <vppinfra/clib.h>
39 #include <vppinfra/error.h>
43 /* Let code below know we've defined _clib_backtrace */
44 #define clib_backtrace_defined
46 #include <vppinfra/asm_mips.h>
49 clib_backtrace (uword * callers,
51 uword n_frames_to_skip)
57 /* Figure current PC, saved PC and stack pointer. */
58 asm volatile (".set push\n"
60 "move %[saved_pc], $31\n"
62 /* Fetches current PC. */
69 [saved_pc] "=r" (saved_pc),
72 /* Also skip current frame. */
73 n_frames_to_skip += 1;
75 for (i = 0; i < max_callers + n_frames_to_skip; i++)
77 mips_insn_opcode_t op;
78 mips_insn_special_funct_t funct;
79 i32 insn, rs, rt, rd, immediate, found_saved_pc;
82 /* Parse instructions until we reach prologue for this
83 stack frame. We'll need to figure out where saved
84 PC is and where previous stack frame lives. */
90 op = mips_insn_get_op (insn);
91 funct = mips_insn_get_funct (insn);
92 rs = mips_insn_get_rs (insn);
93 rt = mips_insn_get_rt (insn);
94 rd = mips_insn_get_rd (insn);
95 immediate = mips_insn_get_immediate (insn);
103 /* Trace stores of return address. */
104 if (rt == MIPS_REG_RA)
106 void * addr = sp + immediate;
108 /* If RA is stored somewhere other than in the
109 stack frame, give up. */
110 if (rs != MIPS_REG_SP)
113 ASSERT (immediate % 4 == 0);
114 if (op == MIPS_OPCODE_sw)
115 saved_pc = ((u32 *) addr)[0];
117 saved_pc = ((u64 *) addr)[0];
122 case MIPS_OPCODE_addiu:
123 case MIPS_OPCODE_daddiu:
124 case MIPS_OPCODE_addi:
125 case MIPS_OPCODE_daddi:
126 if (rt == MIPS_REG_SP)
128 if (rs != MIPS_REG_SP)
131 ASSERT (immediate % 4 == 0);
133 /* Assume positive offset is part of the epilogue.
141 /* Negative offset means allocate stack space.
142 This could either be the prologue or could be due to
146 /* This frame will not save RA. */
150 /* Assume that addiu sp,sp,-N without store of ra means
151 that we have not found the prologue yet. */
157 case MIPS_OPCODE_slti:
158 case MIPS_OPCODE_sltiu:
159 case MIPS_OPCODE_andi:
160 case MIPS_OPCODE_ori:
161 case MIPS_OPCODE_xori:
162 case MIPS_OPCODE_lui:
163 case MIPS_OPCODE_ldl:
164 case MIPS_OPCODE_ldr:
167 case MIPS_OPCODE_lwl:
169 case MIPS_OPCODE_lbu:
170 case MIPS_OPCODE_lhu:
171 case MIPS_OPCODE_lwr:
172 case MIPS_OPCODE_lwu:
174 /* Give up when we find anyone setting the stack pointer. */
175 if (rt == MIPS_REG_SP)
179 case MIPS_OPCODE_SPECIAL:
180 if (rd == MIPS_REG_SP)
183 /* Give up when we find anyone setting the stack pointer. */
186 case MIPS_SPECIAL_FUNCT_break:
187 case MIPS_SPECIAL_FUNCT_jr:
188 case MIPS_SPECIAL_FUNCT_sync:
189 case MIPS_SPECIAL_FUNCT_syscall:
190 case MIPS_SPECIAL_FUNCT_tge:
191 case MIPS_SPECIAL_FUNCT_tgeu:
192 case MIPS_SPECIAL_FUNCT_tlt:
193 case MIPS_SPECIAL_FUNCT_tltu:
194 case MIPS_SPECIAL_FUNCT_teq:
195 case MIPS_SPECIAL_FUNCT_tne:
196 /* These instructions can validly have rd == MIPS_REG_SP */
204 /* Check sanity of saved pc. */
210 if (i >= n_frames_to_skip)
211 callers[i - n_frames_to_skip] = saved_pc;
212 pc = uword_to_pointer (saved_pc, u32 *);
216 if (i < n_frames_to_skip)
219 return i - n_frames_to_skip;
221 #endif /* __mips__ */
223 #ifndef clib_backtrace_defined
224 #define clib_backtrace_defined
226 typedef struct clib_generic_stack_frame_t {
227 struct clib_generic_stack_frame_t * prev;
228 void * return_address;
229 } clib_generic_stack_frame_t;
231 /* This will only work if we have a frame pointer.
232 Without a frame pointer we have to parse the machine code to
233 parse the stack frames. */
235 clib_backtrace (uword * callers,
237 uword n_frames_to_skip)
239 clib_generic_stack_frame_t * f;
242 f = __builtin_frame_address (0);
244 /* Also skip current frame. */
245 n_frames_to_skip += 1;
247 for (i = 0; i < max_callers + n_frames_to_skip; i++)
252 if (clib_abs ((void *) f - (void *) f->prev) > (64*1024))
254 if (i >= n_frames_to_skip)
255 callers[i - n_frames_to_skip] = pointer_to_uword (f->return_address);
259 if (i < n_frames_to_skip)
262 return i - n_frames_to_skip;
264 #endif /* clib_backtrace_defined */