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, uword max_callers, uword n_frames_to_skip)
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. */
63 ".set pop\n":[pc] "=r" (pc),
64 [saved_pc] "=r" (saved_pc),[sp] "=r" (sp));
66 /* Also skip current frame. */
67 n_frames_to_skip += 1;
69 for (i = 0; i < max_callers + n_frames_to_skip; i++)
71 mips_insn_opcode_t op;
72 mips_insn_special_funct_t funct;
73 i32 insn, rs, rt, rd, immediate, found_saved_pc;
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. */
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);
98 /* Trace stores of return address. */
99 if (rt == MIPS_REG_RA)
101 void *addr = sp + immediate;
103 /* If RA is stored somewhere other than in the
104 stack frame, give up. */
105 if (rs != MIPS_REG_SP)
108 ASSERT (immediate % 4 == 0);
109 if (op == MIPS_OPCODE_sw)
110 saved_pc = ((u32 *) addr)[0];
112 saved_pc = ((u64 *) addr)[0];
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)
123 if (rs != MIPS_REG_SP)
126 ASSERT (immediate % 4 == 0);
128 /* Assume positive offset is part of the epilogue.
136 /* Negative offset means allocate stack space.
137 This could either be the prologue or could be due to
141 /* This frame will not save RA. */
145 /* Assume that addiu sp,sp,-N without store of ra means
146 that we have not found the prologue yet. */
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:
162 case MIPS_OPCODE_lwl:
164 case MIPS_OPCODE_lbu:
165 case MIPS_OPCODE_lhu:
166 case MIPS_OPCODE_lwr:
167 case MIPS_OPCODE_lwu:
169 /* Give up when we find anyone setting the stack pointer. */
170 if (rt == MIPS_REG_SP)
174 case MIPS_OPCODE_SPECIAL:
175 if (rd == MIPS_REG_SP)
179 /* Give up when we find anyone setting the stack pointer. */
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 */
200 /* Check sanity of saved pc. */
206 if (i >= n_frames_to_skip)
207 callers[i - n_frames_to_skip] = saved_pc;
208 pc = uword_to_pointer (saved_pc, u32 *);
212 if (i < n_frames_to_skip)
215 return i - n_frames_to_skip;
217 #endif /* __mips__ */
219 #ifndef clib_backtrace_defined
220 #define clib_backtrace_defined
222 typedef struct clib_generic_stack_frame_t
224 struct clib_generic_stack_frame_t *prev;
225 void *return_address;
226 } clib_generic_stack_frame_t;
228 /* This will only work if we have a frame pointer.
229 Without a frame pointer we have to parse the machine code to
230 parse the stack frames. */
232 clib_backtrace (uword * callers, uword max_callers, uword n_frames_to_skip)
234 clib_generic_stack_frame_t *f;
237 f = __builtin_frame_address (0);
239 /* Also skip current frame. */
240 n_frames_to_skip += 1;
242 for (i = 0; i < max_callers + n_frames_to_skip; i++)
247 if (clib_abs ((void *) f - (void *) f->prev) > (64 * 1024))
249 if (i >= n_frames_to_skip)
250 callers[i - n_frames_to_skip] = pointer_to_uword (f->return_address);
254 if (i < n_frames_to_skip)
257 return i - n_frames_to_skip;
259 #endif /* clib_backtrace_defined */
262 * fd.io coding-style-patch-verification: ON
265 * eval: (c-set-style "gnu")