LCOV - code coverage report
Current view: top level - vppinfra - backtrace.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 9 10 90.0 %
Date: 2023-10-26 01:39:38 Functions: 1 1 100.0 %

          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             :  */

Generated by: LCOV version 1.14