FD.io VPP  v21.06-3-gbb25fbf28
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 __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  {
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 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  n_frames_to_skip += 1;
232 
233  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++)
240  {
241  if (i >= n_frames_to_skip)
242  callers[i - n_frames_to_skip] = pointer_to_uword (array[i]);
243  }
244 
245  if (i < n_frames_to_skip)
246  return 0;
247  else
248  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  */
pointer_to_uword
static uword pointer_to_uword(const void *p)
Definition: types.h:131
mips_insn_get_funct
static u32 mips_insn_get_funct(u32 insn)
Definition: asm_mips.h:240
clib.h
addr
vhost_vring_addr_t addr
Definition: vhost_user.h:130
mips_insn_get_rd
static u32 mips_insn_get_rd(u32 insn)
Definition: asm_mips.h:228
i32
signed int i32
Definition: types.h:77
mips_insn_get_immediate
static i32 mips_insn_get_immediate(u32 insn)
Definition: asm_mips.h:246
error.h
ARRAY_LEN
#define ARRAY_LEN(x)
Definition: clib.h:70
mips_insn_special_funct_t
mips_insn_special_funct_t
Definition: asm_mips.h:147
uword
u64 uword
Definition: types.h:112
i
sll srl srl sll sra u16x4 i
Definition: vector_sse42.h:261
mips_insn_opcode_t
mips_insn_opcode_t
Definition: asm_mips.h:140
clib_min
#define clib_min(x, y)
Definition: clib.h:342
mips_insn_get_rs
static u32 mips_insn_get_rs(u32 insn)
Definition: asm_mips.h:216
size
u32 size
Definition: vhost_user.h:125
u64
unsigned long u64
Definition: types.h:89
ASSERT
#define ASSERT(truth)
Definition: error_bootstrap.h:69
MIPS_REG_SP
@ MIPS_REG_SP
Definition: asm_mips.h:339
asm_mips.h
u32
unsigned int u32
Definition: types.h:88
clib_backtrace
__clib_export uword clib_backtrace(uword *callers, uword max_callers, uword n_frames_to_skip)
Definition: backtrace.c:226
rt
vnet_interface_output_runtime_t * rt
Definition: interface_output.c:399
MIPS_REG_RA
@ MIPS_REG_RA
Definition: asm_mips.h:340
uword_to_pointer
#define uword_to_pointer(u, type)
Definition: types.h:136
mips_insn_get_rt
static u32 mips_insn_get_rt(u32 insn)
Definition: asm_mips.h:222
mips_insn_get_op
static mips_insn_opcode_t mips_insn_get_op(u32 insn)
Definition: asm_mips.h:210