FD.io VPP  v16.06
Vector Packet Processing
backtrace.c
Go to the documentation of this file.
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 uword
49 clib_backtrace (uword * callers,
50  uword max_callers,
51  uword n_frames_to_skip)
52 {
53  u32 * pc;
54  void * sp;
55  uword i, saved_pc;
56 
57  /* Figure current PC, saved PC and stack pointer. */
58  asm volatile (".set push\n"
59  ".set noat\n"
60  "move %[saved_pc], $31\n"
61  "move %[sp], $29\n"
62  /* Fetches current PC. */
63  "la $at, 1f\n"
64  "jalr %[pc], $at\n"
65  "nop\n"
66  "1:\n"
67  ".set pop\n"
68  : [pc] "=r" (pc),
69  [saved_pc] "=r" (saved_pc),
70  [sp] "=r" (sp));
71 
72  /* Also skip current frame. */
73  n_frames_to_skip += 1;
74 
75  for (i = 0; i < max_callers + n_frames_to_skip; i++)
76  {
79  i32 insn, rs, rt, rd, immediate, found_saved_pc;
80  u32 * start_pc;
81 
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. */
85  start_pc = pc;
86  found_saved_pc = 0;
87  while (1)
88  {
89  insn = *--pc;
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);
96 
97  switch (op) {
98  default:
99  break;
100 
101  case MIPS_OPCODE_sd:
102  case MIPS_OPCODE_sw:
103  /* Trace stores of return address. */
104  if (rt == MIPS_REG_RA)
105  {
106  void * addr = sp + immediate;
107 
108  /* If RA is stored somewhere other than in the
109  stack frame, give up. */
110  if (rs != MIPS_REG_SP)
111  goto backtrace_done;
112 
113  ASSERT (immediate % 4 == 0);
114  if (op == MIPS_OPCODE_sw)
115  saved_pc = ((u32 *) addr)[0];
116  else
117  saved_pc = ((u64 *) addr)[0];
118  found_saved_pc = 1;
119  }
120  break;
121 
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)
127  {
128  if (rs != MIPS_REG_SP)
129  goto backtrace_done;
130 
131  ASSERT (immediate % 4 == 0);
132 
133  /* Assume positive offset is part of the epilogue.
134  E.g.
135  jr ra
136  add sp,sp,100
137  */
138  if (immediate > 0)
139  continue;
140 
141  /* Negative offset means allocate stack space.
142  This could either be the prologue or could be due to
143  alloca. */
144  sp -= immediate;
145 
146  /* This frame will not save RA. */
147  if (i == 0)
148  goto found_prologue;
149 
150  /* Assume that addiu sp,sp,-N without store of ra means
151  that we have not found the prologue yet. */
152  if (found_saved_pc)
153  goto found_prologue;
154  }
155  break;
156 
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:
165  case MIPS_OPCODE_lb:
166  case MIPS_OPCODE_lh:
167  case MIPS_OPCODE_lwl:
168  case MIPS_OPCODE_lw:
169  case MIPS_OPCODE_lbu:
170  case MIPS_OPCODE_lhu:
171  case MIPS_OPCODE_lwr:
172  case MIPS_OPCODE_lwu:
173  case MIPS_OPCODE_ld:
174  /* Give up when we find anyone setting the stack pointer. */
175  if (rt == MIPS_REG_SP)
176  goto backtrace_done;
177  break;
178 
179  case MIPS_OPCODE_SPECIAL:
180  if (rd == MIPS_REG_SP)
181  switch (funct) {
182  default:
183  /* Give up when we find anyone setting the stack pointer. */
184  goto backtrace_done;
185 
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 */
197  break;
198  }
199  break;
200  }
201  }
202 
203  found_prologue:
204  /* Check sanity of saved pc. */
205  if (saved_pc & 3)
206  goto backtrace_done;
207  if (saved_pc == 0)
208  goto backtrace_done;
209 
210  if (i >= n_frames_to_skip)
211  callers[i - n_frames_to_skip] = saved_pc;
212  pc = uword_to_pointer (saved_pc, u32 *);
213  }
214 
215  backtrace_done:
216  if (i < n_frames_to_skip)
217  return 0;
218  else
219  return i - n_frames_to_skip;
220 }
221 #endif /* __mips__ */
222 
223 #ifndef clib_backtrace_defined
224 #define clib_backtrace_defined
225 
230 
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. */
234 uword
236  uword max_callers,
237  uword n_frames_to_skip)
238 {
240  uword i;
241 
242  f = __builtin_frame_address (0);
243 
244  /* Also skip current frame. */
245  n_frames_to_skip += 1;
246 
247  for (i = 0; i < max_callers + n_frames_to_skip; i++)
248  {
249  f = f->prev;
250  if (! f)
251  goto backtrace_done;
252  if (clib_abs ((void *) f - (void *) f->prev) > (64*1024))
253  goto backtrace_done;
254  if (i >= n_frames_to_skip)
255  callers[i - n_frames_to_skip] = pointer_to_uword (f->return_address);
256  }
257 
258  backtrace_done:
259  if (i < n_frames_to_skip)
260  return 0;
261  else
262  return i - n_frames_to_skip;
263 }
264 #endif /* clib_backtrace_defined */
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
struct clib_generic_stack_frame_t clib_generic_stack_frame_t
uword clib_backtrace(uword *callers, uword max_callers, uword n_frames_to_skip)
Definition: backtrace.c:235
#define clib_abs(x)
Definition: clib.h:302
always_inline u32 mips_insn_get_funct(u32 insn)
Definition: asm_mips.h:220
always_inline u32 mips_insn_get_rs(u32 insn)
Definition: asm_mips.h:204
mips_insn_opcode_t
Definition: asm_mips.h:140
struct clib_generic_stack_frame_t * prev
Definition: backtrace.c:227
int i32
Definition: types.h:81
always_inline mips_insn_opcode_t mips_insn_get_op(u32 insn)
Definition: asm_mips.h:200
unsigned long u64
Definition: types.h:89
static uword pointer_to_uword(const void *p)
Definition: types.h:131
always_inline u32 mips_insn_get_rt(u32 insn)
Definition: asm_mips.h:208
#define uword_to_pointer(u, type)
Definition: types.h:134
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
mips_insn_special_funct_t
Definition: asm_mips.h:146
u64 uword
Definition: types.h:112
always_inline i32 mips_insn_get_immediate(u32 insn)
Definition: asm_mips.h:224
always_inline u32 mips_insn_get_rd(u32 insn)
Definition: asm_mips.h:212