LCOV - code coverage report
Current view: top level - libdwfl - frame_unwind.c (source / functions) Hit Total Coverage
Test: elfutils-0.191 Lines: 275 400 68.8 %
Date: 2024-03-01 16:42:08 Functions: 12 12 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 235 398 59.0 %

           Branch data     Line data    Source code
       1                 :            : /* Get previous frame state for an existing frame state.
       2                 :            :    Copyright (C) 2013, 2014, 2016 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            : 
       5                 :            :    This file is free software; you can redistribute it and/or modify
       6                 :            :    it under the terms of either
       7                 :            : 
       8                 :            :      * the GNU Lesser General Public License as published by the Free
       9                 :            :        Software Foundation; either version 3 of the License, or (at
      10                 :            :        your option) any later version
      11                 :            : 
      12                 :            :    or
      13                 :            : 
      14                 :            :      * the GNU General Public License as published by the Free
      15                 :            :        Software Foundation; either version 2 of the License, or (at
      16                 :            :        your option) any later version
      17                 :            : 
      18                 :            :    or both in parallel, as here.
      19                 :            : 
      20                 :            :    elfutils is distributed in the hope that it will be useful, but
      21                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23                 :            :    General Public License for more details.
      24                 :            : 
      25                 :            :    You should have received copies of the GNU General Public License and
      26                 :            :    the GNU Lesser General Public License along with this program.  If
      27                 :            :    not, see <http://www.gnu.org/licenses/>.  */
      28                 :            : 
      29                 :            : #ifdef HAVE_CONFIG_H
      30                 :            : # include <config.h>
      31                 :            : #endif
      32                 :            : 
      33                 :            : #include "cfi.h"
      34                 :            : #include <stdlib.h>
      35                 :            : #include "libdwflP.h"
      36                 :            : #include "dwarf.h"
      37                 :            : #include <system.h>
      38                 :            : 
      39                 :            : /* Maximum number of DWARF expression stack slots before returning an error.  */
      40                 :            : #define DWARF_EXPR_STACK_MAX 0x100
      41                 :            : 
      42                 :            : /* Maximum number of DWARF expression executed operations before returning an
      43                 :            :    error.  */
      44                 :            : #define DWARF_EXPR_STEPS_MAX 0x1000
      45                 :            : 
      46                 :            : int
      47                 :            : internal_function
      48                 :       7584 : __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val)
      49                 :            : {
      50                 :       7584 :   Ebl *ebl = state->thread->process->ebl;
      51         [ +  + ]:       7584 :   if (! ebl_dwarf_to_regno (ebl, &regno))
      52                 :         16 :     return -1;
      53         [ -  + ]:       7568 :   if (regno >= ebl_frame_nregs (ebl))
      54                 :          0 :     return -1;
      55                 :       7568 :   if ((state->regs_set[regno / sizeof (*state->regs_set) / 8]
      56         [ +  + ]:       7568 :        & ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)))) == 0)
      57                 :       3370 :     return 1;
      58         [ +  - ]:       4198 :   if (val)
      59                 :       4198 :     *val = state->regs[regno];
      60                 :       4198 :   return 0;
      61                 :            : }
      62                 :            : 
      63                 :            : bool
      64                 :            : internal_function
      65                 :       5596 : __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, Dwarf_Addr val)
      66                 :            : {
      67                 :       5596 :   Ebl *ebl = state->thread->process->ebl;
      68         [ +  + ]:       5596 :   if (! ebl_dwarf_to_regno (ebl, &regno))
      69                 :         16 :     return false;
      70         [ -  + ]:       5580 :   if (regno >= ebl_frame_nregs (ebl))
      71                 :          0 :     return false;
      72                 :            :   /* For example i386 user_regs_struct has signed fields.  */
      73         [ +  + ]:       5580 :   if (ebl_get_elfclass (ebl) == ELFCLASS32)
      74                 :       1402 :     val &= 0xffffffff;
      75                 :       5580 :   state->regs_set[regno / sizeof (*state->regs_set) / 8] |=
      76                 :       5580 :                 ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)));
      77                 :       5580 :   state->regs[regno] = val;
      78                 :       5580 :   return true;
      79                 :            : }
      80                 :            : 
      81                 :            : static int
      82                 :        936 : bra_compar (const void *key_voidp, const void *elem_voidp)
      83                 :            : {
      84                 :        936 :   Dwarf_Word offset = (uintptr_t) key_voidp;
      85                 :        936 :   const Dwarf_Op *op = elem_voidp;
      86                 :        936 :   return (offset > op->offset) - (offset < op->offset);
      87                 :            : }
      88                 :            : 
      89                 :            : struct eval_stack {
      90                 :            :   Dwarf_Addr *addrs;
      91                 :            :   size_t used;
      92                 :            :   size_t allocated;
      93                 :            : };
      94                 :            : 
      95                 :            : static bool
      96                 :       5066 : do_push (struct eval_stack *stack, Dwarf_Addr val)
      97                 :            : {
      98         [ -  + ]:       5066 :   if (stack->used >= DWARF_EXPR_STACK_MAX)
      99                 :            :     {
     100                 :          0 :       __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     101                 :          0 :       return false;
     102                 :            :     }
     103         [ +  + ]:       5066 :   if (stack->used == stack->allocated)
     104                 :            :     {
     105                 :       3252 :       stack->allocated = MAX (stack->allocated * 2, 32);
     106                 :            :       Dwarf_Addr *new_addrs;
     107                 :       3252 :       new_addrs = realloc (stack->addrs,
     108                 :       3252 :                            stack->allocated * sizeof (*stack->addrs));
     109         [ -  + ]:       3252 :       if (new_addrs == NULL)
     110                 :            :         {
     111                 :          0 :           __libdwfl_seterrno (DWFL_E_NOMEM);
     112                 :          0 :           return false;
     113                 :            :         }
     114                 :       3252 :       stack->addrs = new_addrs;
     115                 :            :     }
     116                 :       5066 :   stack->addrs[stack->used++] = val;
     117                 :       5066 :   return true;
     118                 :            : }
     119                 :            : 
     120                 :            : static bool
     121                 :       5066 : do_pop (struct eval_stack *stack, Dwarf_Addr *val)
     122                 :            : {
     123         [ -  + ]:       5066 :   if (stack->used == 0)
     124                 :            :     {
     125                 :          0 :       __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     126                 :          0 :       return false;
     127                 :            :     }
     128                 :       5066 :   *val = stack->addrs[--stack->used];
     129                 :       5066 :   return true;
     130                 :            : }
     131                 :            : 
     132                 :            : /* If FRAME is NULL is are computing CFI frame base.  In such case another
     133                 :            :    DW_OP_call_frame_cfa is no longer permitted.  */
     134                 :            : 
     135                 :            : static bool
     136                 :       3272 : expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
     137                 :            :            size_t nops, Dwarf_Addr *result, Dwarf_Addr bias)
     138                 :            : {
     139                 :       3272 :   Dwfl_Process *process = state->thread->process;
     140         [ -  + ]:       3272 :   if (nops == 0)
     141                 :            :     {
     142                 :          0 :       __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     143                 :          0 :       return false;
     144                 :            :     }
     145                 :       3272 :   struct eval_stack stack =
     146                 :            :     {
     147                 :            :       .addrs = NULL,
     148                 :            :       .used = 0,
     149                 :            :       .allocated = 0
     150                 :            :     };
     151                 :            : 
     152                 :            : #define pop(x) do_pop(&stack, x)
     153                 :            : #define push(x) do_push(&stack, x)
     154                 :            : 
     155                 :            :   Dwarf_Addr val1, val2;
     156                 :       3272 :   bool is_location = false;
     157                 :       3272 :   size_t steps_count = 0;
     158         [ +  + ]:       8720 :   for (const Dwarf_Op *op = ops; op < ops + nops; op++)
     159                 :            :     {
     160         [ -  + ]:       5468 :       if (++steps_count > DWARF_EXPR_STEPS_MAX)
     161                 :            :         {
     162                 :          0 :           __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     163                 :          0 :           return false;
     164                 :            :         }
     165   [ +  -  -  +  :       5468 :       switch (op->atom)
          -  +  -  +  +  
          +  +  +  +  +  
          -  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  -  +  
                +  +  - ]
     166                 :            :       {
     167                 :            :         /* DW_OP_* order matches libgcc/unwind-dw2.c execute_stack_op:  */
     168                 :        228 :         case DW_OP_lit0 ... DW_OP_lit31:
     169         [ -  + ]:        228 :           if (! push (op->atom - DW_OP_lit0))
     170                 :            :             {
     171                 :          0 :               free (stack.addrs);
     172                 :         20 :               return false;
     173                 :            :             }
     174                 :       5448 :           break;
     175                 :          0 :         case DW_OP_addr:
     176         [ #  # ]:          0 :           if (! push (op->number + bias))
     177                 :            :             {
     178                 :          0 :               free (stack.addrs);
     179                 :          0 :               return false;
     180                 :            :             }
     181                 :          0 :           break;
     182                 :          0 :         case DW_OP_GNU_encoded_addr:
     183                 :            :           /* Missing support in the rest of elfutils.  */
     184                 :          0 :           __libdwfl_seterrno (DWFL_E_UNSUPPORTED_DWARF);
     185                 :          0 :           return false;
     186                 :         70 :         case DW_OP_const1u:
     187                 :            :         case DW_OP_const1s:
     188                 :            :         case DW_OP_const2u:
     189                 :            :         case DW_OP_const2s:
     190                 :            :         case DW_OP_const4u:
     191                 :            :         case DW_OP_const4s:
     192                 :            :         case DW_OP_const8u:
     193                 :            :         case DW_OP_const8s:
     194                 :            :         case DW_OP_constu:
     195                 :            :         case DW_OP_consts:
     196         [ -  + ]:         70 :           if (! push (op->number))
     197                 :            :             {
     198                 :          0 :               free (stack.addrs);
     199                 :          0 :               return false;
     200                 :            :             }
     201                 :         70 :           break;
     202                 :          0 :         case DW_OP_reg0 ... DW_OP_reg31:
     203         [ #  # ]:          0 :           if (INTUSE (dwfl_frame_reg) (state, op->atom - DW_OP_reg0, &val1) != 0
     204         [ #  # ]:          0 :               || ! push (val1))
     205                 :            :             {
     206                 :          0 :               free (stack.addrs);
     207                 :          0 :               return false;
     208                 :            :             }
     209                 :          0 :           break;
     210                 :        144 :         case DW_OP_regx:
     211   [ +  -  -  + ]:        144 :           if (INTUSE (dwfl_frame_reg) (state, op->number, &val1) != 0 || ! push (val1))
     212                 :            :             {
     213                 :          0 :               free (stack.addrs);
     214                 :          0 :               return false;
     215                 :            :             }
     216                 :        144 :           break;
     217                 :          0 :         case DW_OP_breg0 ... DW_OP_breg31:
     218         [ #  # ]:          0 :           if (INTUSE (dwfl_frame_reg) (state, op->atom - DW_OP_breg0, &val1) != 0)
     219                 :            :             {
     220                 :          0 :               free (stack.addrs);
     221                 :          0 :               return false;
     222                 :            :             }
     223                 :          0 :           val1 += op->number;
     224         [ #  # ]:          0 :           if (! push (val1))
     225                 :            :             {
     226                 :          0 :               free (stack.addrs);
     227                 :          0 :               return false;
     228                 :            :             }
     229                 :          0 :           break;
     230                 :       1564 :         case DW_OP_bregx:
     231         [ +  + ]:       1564 :           if (INTUSE (dwfl_frame_reg) (state, op->number, &val1) != 0)
     232                 :            :             {
     233                 :         10 :               free (stack.addrs);
     234                 :         10 :               return false;
     235                 :            :             }
     236                 :       1554 :           val1 += op->number2;
     237         [ -  + ]:       1554 :           if (! push (val1))
     238                 :            :             {
     239                 :          0 :               free (stack.addrs);
     240                 :          0 :               return false;
     241                 :            :             }
     242                 :       1554 :           break;
     243                 :          2 :         case DW_OP_dup:
     244   [ +  -  +  -  :          2 :           if (! pop (&val1) || ! push (val1) || ! push (val1))
                   -  + ]
     245                 :            :             {
     246                 :          0 :               free (stack.addrs);
     247                 :          0 :               return false;
     248                 :            :             }
     249                 :          2 :           break;
     250                 :          2 :         case DW_OP_drop:
     251         [ -  + ]:          2 :           if (! pop (&val1))
     252                 :            :             {
     253                 :          0 :               free (stack.addrs);
     254                 :          0 :               return false;
     255                 :            :             }
     256                 :          2 :           break;
     257                 :          4 :         case DW_OP_pick:
     258         [ -  + ]:          4 :           if (stack.used <= op->number)
     259                 :            :             {
     260                 :          0 :               free (stack.addrs);
     261                 :          0 :               __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     262                 :          0 :               return false;
     263                 :            :             }
     264         [ -  + ]:          4 :           if (! push (stack.addrs[stack.used - 1 - op->number]))
     265                 :            :             {
     266                 :          0 :               free (stack.addrs);
     267                 :          0 :               return false;
     268                 :            :             }
     269                 :          4 :           break;
     270                 :         14 :         case DW_OP_over:
     271   [ +  -  +  - ]:         14 :           if (! pop (&val1) || ! pop (&val2)
     272   [ +  -  +  -  :         14 :               || ! push (val2) || ! push (val1) || ! push (val2))
                   -  + ]
     273                 :            :             {
     274                 :          0 :               free (stack.addrs);
     275                 :          0 :               return false;
     276                 :            :             }
     277                 :         14 :           break;
     278                 :          2 :         case DW_OP_swap:
     279   [ +  -  +  -  :          2 :           if (! pop (&val1) || ! pop (&val2) || ! push (val1) || ! push (val2))
             +  -  -  + ]
     280                 :            :             {
     281                 :          0 :               free (stack.addrs);
     282                 :          0 :               return false;
     283                 :            :             }
     284                 :          2 :           break;
     285                 :          2 :         case DW_OP_rot:
     286                 :            :           {
     287                 :            :             Dwarf_Addr val3;
     288   [ +  -  +  -  :          2 :             if (! pop (&val1) || ! pop (&val2) || ! pop (&val3)
                   +  - ]
     289   [ +  -  +  -  :          2 :                 || ! push (val1) || ! push (val3) || ! push (val2))
                   -  + ]
     290                 :            :               {
     291                 :          0 :                 free (stack.addrs);
     292                 :          0 :                 return false;
     293                 :            :               }
     294                 :            :           }
     295                 :          2 :           break;
     296                 :          0 :         case DW_OP_deref:
     297                 :            :         case DW_OP_deref_size:
     298         [ #  # ]:          0 :           if (process->callbacks->memory_read == NULL)
     299                 :            :             {
     300                 :          0 :               free (stack.addrs);
     301                 :          0 :               __libdwfl_seterrno (DWFL_E_INVALID_ARGUMENT);
     302                 :          0 :               return false;
     303                 :            :             }
     304         [ #  # ]:          0 :           if (! pop (&val1)
     305         [ #  # ]:          0 :               || ! process->callbacks->memory_read (process->dwfl, val1, &val1,
     306                 :            :                                                     process->callbacks_arg))
     307                 :            :             {
     308                 :          0 :               free (stack.addrs);
     309                 :          0 :               return false;
     310                 :            :             }
     311         [ #  # ]:          0 :           if (op->atom == DW_OP_deref_size)
     312                 :            :             {
     313                 :          0 :               const int elfclass = frame->cache->e_ident[EI_CLASS];
     314         [ #  # ]:          0 :               const unsigned addr_bytes = elfclass == ELFCLASS32 ? 4 : 8;
     315         [ #  # ]:          0 :               if (op->number > addr_bytes)
     316                 :            :                 {
     317                 :          0 :                   free (stack.addrs);
     318                 :          0 :                   __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     319                 :          0 :                   return false;
     320                 :            :                 }
     321                 :            : #if BYTE_ORDER == BIG_ENDIAN
     322                 :            :               if (op->number == 0)
     323                 :            :                 val1 = 0;
     324                 :            :               else
     325                 :            :                 val1 >>= (addr_bytes - op->number) * 8;
     326                 :            : #else
     327         [ #  # ]:          0 :               if (op->number < 8)
     328                 :          0 :                 val1 &= (1ULL << (op->number * 8)) - 1;
     329                 :            : #endif
     330                 :            :             }
     331         [ #  # ]:          0 :           if (! push (val1))
     332                 :            :             {
     333                 :          0 :               free (stack.addrs);
     334                 :          0 :               return false;
     335                 :            :             }
     336                 :          0 :           break;
     337                 :            : #define UNOP(atom, expr)                                                \
     338                 :            :         case atom:                                                      \
     339                 :            :           if (! pop (&val1) || ! push (expr))                               \
     340                 :            :             {                                                           \
     341                 :            :               free (stack.addrs);                                       \
     342                 :            :               return false;                                             \
     343                 :            :             }                                                           \
     344                 :            :           break;
     345   [ +  -  -  + ]:          4 :         UNOP (DW_OP_abs, llabs ((int64_t) val1))
     346   [ +  -  -  + ]:          6 :         UNOP (DW_OP_neg, -(int64_t) val1)
     347   [ +  -  -  + ]:          2 :         UNOP (DW_OP_not, ~val1)
     348                 :            : #undef UNOP
     349                 :       1250 :         case DW_OP_plus_uconst:
     350   [ +  -  -  + ]:       1250 :           if (! pop (&val1) || ! push (val1 + op->number))
     351                 :            :             {
     352                 :          0 :               free (stack.addrs);
     353                 :          0 :               return false;
     354                 :            :             }
     355                 :       1250 :           break;
     356                 :            : #define BINOP(atom, op)                                                 \
     357                 :            :         case atom:                                                      \
     358                 :            :           if (! pop (&val2) || ! pop (&val1) || ! push (val1 op val2))  \
     359                 :            :             {                                                           \
     360                 :            :               free (stack.addrs);                                       \
     361                 :            :               return false;                                             \
     362                 :            :             }                                                           \
     363                 :            :           break;
     364                 :            : #define BINOP_SIGNED(atom, op)                                          \
     365                 :            :         case atom:                                                      \
     366                 :            :           if (! pop (&val2) || ! pop (&val1)                            \
     367                 :            :               || ! push ((int64_t) val1 op (int64_t) val2))             \
     368                 :            :             {                                                           \
     369                 :            :               free (stack.addrs);                                       \
     370                 :            :               return false;                                             \
     371                 :            :             }                                                           \
     372                 :            :           break;
     373   [ +  -  +  -  :          4 :         BINOP (DW_OP_and, &)
                   -  + ]
     374                 :         10 :         case DW_OP_div:
     375   [ +  -  -  + ]:         10 :           if (! pop (&val2) || ! pop (&val1))
     376                 :            :             {
     377                 :          0 :               free (stack.addrs);
     378                 :          0 :               return false;
     379                 :            :             }
     380         [ -  + ]:         10 :           if (val2 == 0)
     381                 :            :             {
     382                 :          0 :               free (stack.addrs);
     383                 :          0 :               __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     384                 :          0 :               return false;
     385                 :            :             }
     386         [ -  + ]:         10 :           if (! push ((int64_t) val1 / (int64_t) val2))
     387                 :            :             {
     388                 :          0 :               free (stack.addrs);
     389                 :          0 :               return false;
     390                 :            :             }
     391                 :         10 :           break;
     392   [ +  -  +  -  :         10 :         BINOP (DW_OP_minus, -)
                   -  + ]
     393                 :          6 :         case DW_OP_mod:
     394   [ +  -  -  + ]:          6 :           if (! pop (&val2) || ! pop (&val1))
     395                 :            :             {
     396                 :          0 :               free (stack.addrs);
     397                 :          0 :               return false;
     398                 :            :             }
     399         [ -  + ]:          6 :           if (val2 == 0)
     400                 :            :             {
     401                 :          0 :               free (stack.addrs);
     402                 :          0 :               __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     403                 :          0 :               return false;
     404                 :            :             }
     405         [ -  + ]:          6 :           if (! push (val1 % val2))
     406                 :            :             {
     407                 :          0 :               free (stack.addrs);
     408                 :          0 :               return false;
     409                 :            :             }
     410                 :          6 :           break;
     411   [ +  -  +  -  :          8 :         BINOP (DW_OP_mul, *)
                   -  + ]
     412   [ +  -  +  -  :          2 :         BINOP (DW_OP_or, |)
                   -  + ]
     413   [ +  -  +  -  :          4 :         BINOP (DW_OP_plus, +)
                   -  + ]
     414   [ +  -  +  -  :          2 :         BINOP (DW_OP_shl, <<)
                   -  + ]
     415   [ +  -  +  -  :          4 :         BINOP (DW_OP_shr, >>)
                   -  + ]
     416   [ +  -  +  -  :          4 :         BINOP_SIGNED (DW_OP_shra, >>)
                   -  + ]
     417   [ +  -  +  -  :          2 :         BINOP (DW_OP_xor, ^)
                   -  + ]
     418   [ +  -  +  -  :          6 :         BINOP_SIGNED (DW_OP_le, <=)
                   -  + ]
     419   [ +  -  +  -  :          6 :         BINOP_SIGNED (DW_OP_ge, >=)
                   -  + ]
     420   [ +  -  +  -  :        104 :         BINOP_SIGNED (DW_OP_eq, ==)
                   -  + ]
     421   [ +  -  +  -  :          8 :         BINOP_SIGNED (DW_OP_lt, <)
                   -  + ]
     422   [ +  -  +  -  :          8 :         BINOP_SIGNED (DW_OP_gt, >)
                   -  + ]
     423   [ +  -  +  -  :          6 :         BINOP_SIGNED (DW_OP_ne, !=)
                   -  + ]
     424                 :            : #undef BINOP
     425                 :            : #undef BINOP_SIGNED
     426                 :        122 :         case DW_OP_bra:
     427         [ -  + ]:        122 :           if (! pop (&val1))
     428                 :            :             {
     429                 :          0 :               free (stack.addrs);
     430                 :          0 :               return false;
     431                 :            :             }
     432         [ -  + ]:        122 :           if (val1 == 0)
     433                 :          0 :             break;
     434                 :            :           FALLTHROUGH;
     435                 :            :         case DW_OP_skip:;
     436                 :        122 :           Dwarf_Word offset = op->offset + 1 + 2 + (int16_t) op->number;
     437                 :        122 :           const Dwarf_Op *found = bsearch ((void *) (uintptr_t) offset, ops, nops,
     438                 :            :                                            sizeof (*ops), bra_compar);
     439         [ -  + ]:        122 :           if (found == NULL)
     440                 :            :             {
     441                 :          0 :               free (stack.addrs);
     442                 :            :               /* PPC32 vDSO has such invalid operations.  */
     443                 :          0 :               __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     444                 :          0 :               return false;
     445                 :            :             }
     446                 :            :           /* Undo the 'for' statement increment.  */
     447                 :        122 :           op = found - 1;
     448                 :        122 :           break;
     449                 :          4 :         case DW_OP_nop:
     450                 :          4 :           break;
     451                 :            :         /* DW_OP_* not listed in libgcc/unwind-dw2.c execute_stack_op:  */
     452                 :       1564 :         case DW_OP_call_frame_cfa:;
     453                 :            :           // Not used by CFI itself but it is synthetized by elfutils internation.
     454                 :            :           Dwarf_Op *cfa_ops;
     455                 :            :           size_t cfa_nops;
     456                 :            :           Dwarf_Addr cfa;
     457         [ +  - ]:       1564 :           if (frame == NULL
     458         [ +  - ]:       1564 :               || dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0
     459         [ +  + ]:       1564 :               || ! expr_eval (state, NULL, cfa_ops, cfa_nops, &cfa, bias)
     460         [ -  + ]:       1554 :               || ! push (cfa))
     461                 :            :             {
     462                 :         10 :               __libdwfl_seterrno (DWFL_E_LIBDW);
     463                 :         10 :               free (stack.addrs);
     464                 :         10 :               return false;
     465                 :            :             }
     466                 :       1554 :           is_location = true;
     467                 :       1554 :           break;
     468                 :        290 :         case DW_OP_stack_value:
     469                 :            :           // Not used by CFI itself but it is synthetized by elfutils internation.
     470                 :        290 :           is_location = false;
     471                 :        290 :           break;
     472                 :          0 :         default:
     473                 :          0 :           __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     474                 :          0 :           return false;
     475                 :            :       }
     476                 :            :     }
     477         [ -  + ]:       3252 :   if (! pop (result))
     478                 :            :     {
     479                 :          0 :       free (stack.addrs);
     480                 :          0 :       return false;
     481                 :            :     }
     482                 :       3252 :   free (stack.addrs);
     483         [ +  + ]:       3252 :   if (is_location)
     484                 :            :     {
     485         [ -  + ]:       1264 :       if (process->callbacks->memory_read == NULL)
     486                 :            :         {
     487                 :          0 :           __libdwfl_seterrno (DWFL_E_INVALID_ARGUMENT);
     488                 :          0 :           return false;
     489                 :            :         }
     490         [ +  + ]:       1264 :       if (! process->callbacks->memory_read (process->dwfl, *result, result,
     491                 :            :                                              process->callbacks_arg))
     492                 :         12 :         return false;
     493                 :            :     }
     494                 :       3240 :   return true;
     495                 :            : #undef push
     496                 :            : #undef pop
     497                 :            : }
     498                 :            : 
     499                 :            : static Dwfl_Frame *
     500                 :        470 : new_unwound (Dwfl_Frame *state)
     501                 :            : {
     502         [ -  + ]:        470 :   assert (state->unwound == NULL);
     503                 :        470 :   Dwfl_Thread *thread = state->thread;
     504                 :        470 :   Dwfl_Process *process = thread->process;
     505                 :        470 :   Ebl *ebl = process->ebl;
     506                 :        470 :   size_t nregs = ebl_frame_nregs (ebl);
     507         [ -  + ]:        470 :   assert (nregs > 0);
     508                 :            :   Dwfl_Frame *unwound;
     509                 :        470 :   unwound = malloc (sizeof (*unwound) + sizeof (*unwound->regs) * nregs);
     510         [ -  + ]:        470 :   if (unlikely (unwound == NULL))
     511                 :          0 :     return NULL;
     512                 :        470 :   state->unwound = unwound;
     513                 :        470 :   unwound->thread = thread;
     514                 :        470 :   unwound->unwound = NULL;
     515                 :        470 :   unwound->signal_frame = false;
     516                 :        470 :   unwound->initial_frame = false;
     517                 :        470 :   unwound->pc_state = DWFL_FRAME_STATE_ERROR;
     518                 :        470 :   memset (unwound->regs_set, 0, sizeof (unwound->regs_set));
     519                 :        470 :   return unwound;
     520                 :            : }
     521                 :            : 
     522                 :            : /* The logic is to call __libdwfl_seterrno for any CFI bytecode interpretation
     523                 :            :    error so one can easily catch the problem with a debugger.  Still there are
     524                 :            :    archs with invalid CFI for some registers where the registers are never used
     525                 :            :    later.  Therefore we continue unwinding leaving the registers undefined.  */
     526                 :            : 
     527                 :            : static void
     528                 :        520 : handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
     529                 :            : {
     530                 :            :   Dwarf_Frame *frame;
     531         [ +  + ]:        520 :   if (INTUSE(dwarf_cfi_addrframe) (cfi, pc, &frame) != 0)
     532                 :            :     {
     533                 :        174 :       __libdwfl_seterrno (DWFL_E_LIBDW);
     534                 :        174 :       return;
     535                 :            :     }
     536                 :            : 
     537                 :        346 :   Dwfl_Frame *unwound = new_unwound (state);
     538         [ -  + ]:        346 :   if (unwound == NULL)
     539                 :            :     {
     540                 :          0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     541                 :          0 :       return;
     542                 :            :     }
     543                 :            : 
     544                 :        346 :   unwound->signal_frame = frame->fde->cie->signal_frame;
     545                 :        346 :   Dwfl_Thread *thread = state->thread;
     546                 :        346 :   Dwfl_Process *process = thread->process;
     547                 :        346 :   Ebl *ebl = process->ebl;
     548                 :        346 :   size_t nregs = ebl_frame_nregs (ebl);
     549         [ -  + ]:        346 :   assert (nregs > 0);
     550                 :            : 
     551                 :            :   /* The return register is special for setting the unwound->pc_state.  */
     552                 :        346 :   unsigned ra = frame->fde->cie->return_address_register;
     553                 :        346 :   bool ra_set = false;
     554         [ -  + ]:        346 :   if (! ebl_dwarf_to_regno (ebl, &ra))
     555                 :            :     {
     556                 :          0 :       __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
     557                 :          0 :       return;
     558                 :            :     }
     559                 :            : 
     560         [ +  + ]:      13420 :   for (unsigned regno = 0; regno < nregs; regno++)
     561                 :            :     {
     562                 :            :       Dwarf_Op reg_ops_mem[3], *reg_ops;
     563                 :            :       size_t reg_nops;
     564         [ -  + ]:      13074 :       if (dwarf_frame_register (frame, regno, reg_ops_mem, &reg_ops,
     565                 :            :                                 &reg_nops) != 0)
     566                 :            :         {
     567                 :          0 :           __libdwfl_seterrno (DWFL_E_LIBDW);
     568                 :       9390 :           continue;
     569                 :            :         }
     570                 :            :       Dwarf_Addr regval;
     571         [ +  + ]:      13074 :       if (reg_nops == 0)
     572                 :            :         {
     573         [ +  + ]:      11366 :           if (reg_ops == reg_ops_mem)
     574                 :            :             {
     575                 :            :               /* REGNO is undefined.  */
     576         [ +  + ]:       7596 :               if (regno == ra)
     577                 :         30 :                 unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     578                 :       7596 :               continue;
     579                 :            :             }
     580         [ +  - ]:       3770 :           else if (reg_ops == NULL)
     581                 :            :             {
     582                 :            :               /* REGNO is same-value.  */
     583         [ +  + ]:       3770 :               if (INTUSE (dwfl_frame_reg) (state, regno, &regval) != 0)
     584                 :       1772 :                 continue;
     585                 :            :             }
     586                 :            :           else
     587                 :            :             {
     588                 :          0 :               __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     589                 :          0 :               continue;
     590                 :            :             }
     591                 :            :         }
     592         [ +  + ]:       1708 :       else if (! expr_eval (state, frame, reg_ops, reg_nops, &regval, bias))
     593                 :            :         {
     594                 :            :           /* PPC32 vDSO has various invalid operations, ignore them.  The
     595                 :            :              register will look as unset causing an error later, if used.
     596                 :            :              But PPC32 does not use such registers.  */
     597                 :         22 :           continue;
     598                 :            :         }
     599                 :            : 
     600                 :            :       /* Some architectures encode some extra info in the return address.  */
     601         [ +  + ]:       3684 :       if (regno == frame->fde->cie->return_address_register)
     602                 :        312 :         regval &= ebl_func_addr_mask (ebl);
     603                 :            : 
     604                 :            :       /* This is another strange PPC[64] case.  There are two
     605                 :            :          registers numbers that can represent the same DWARF return
     606                 :            :          register number.  We only want one to actually set the return
     607                 :            :          register value.  But we always want to override the value if
     608                 :            :          the register is the actual CIE return address register.  */
     609   [ +  +  +  - ]:       3684 :       if (ra_set && regno != frame->fde->cie->return_address_register)
     610                 :            :         {
     611                 :        418 :           unsigned r = regno;
     612   [ +  -  -  + ]:        418 :           if (ebl_dwarf_to_regno (ebl, &r) && r == ra)
     613                 :          0 :             continue;
     614                 :            :         }
     615                 :            : 
     616         [ -  + ]:       3684 :       if (! __libdwfl_frame_reg_set (unwound, regno, regval))
     617                 :            :         {
     618                 :          0 :           __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
     619                 :          0 :           continue;
     620                 :            :         }
     621         [ +  + ]:       3684 :       else if (! ra_set)
     622                 :            :         {
     623                 :       3266 :           unsigned r = regno;
     624   [ +  -  +  + ]:       3266 :           if (ebl_dwarf_to_regno (ebl, &r) && r == ra)
     625                 :        312 :             ra_set = true;
     626                 :            :         }
     627                 :            :     }
     628         [ +  + ]:        346 :   if (unwound->pc_state == DWFL_FRAME_STATE_ERROR)
     629                 :            :     {
     630                 :        316 :       int res = INTUSE (dwfl_frame_reg) (unwound,
     631                 :        316 :           frame->fde->cie->return_address_register,
     632                 :        316 :           &unwound->pc);
     633         [ +  + ]:        316 :       if (res == 0)
     634                 :            :         {
     635                 :            :           /* PPC32 __libc_start_main properly CFI-unwinds PC as zero.
     636                 :            :              Currently none of the archs supported for unwinding have
     637                 :            :              zero as a valid PC.  */
     638         [ +  + ]:        312 :           if (unwound->pc == 0)
     639                 :          2 :             unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     640                 :            :           else
     641                 :            :             {
     642                 :        310 :               unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
     643                 :            :               /* In SPARC the return address register actually contains
     644                 :            :                  the address of the call instruction instead of the return
     645                 :            :                  address.  Therefore we add here an offset defined by the
     646                 :            :                  backend.  Most likely 0.  */
     647                 :        310 :               unwound->pc += ebl_ra_offset (ebl);
     648                 :            :             }
     649                 :            :         }
     650                 :            :       else
     651                 :            :         {
     652                 :            :           /* We couldn't set the return register, either it was bogus,
     653                 :            :              or the return pc is undefined, maybe end of call stack.  */
     654                 :          4 :           unsigned pcreg = frame->fde->cie->return_address_register;
     655         [ +  - ]:          4 :           if (! ebl_dwarf_to_regno (ebl, &pcreg)
     656         [ -  + ]:          4 :               || pcreg >= ebl_frame_nregs (ebl))
     657                 :          0 :             __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
     658                 :            :           else
     659                 :          4 :             unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     660                 :            :         }
     661                 :            :     }
     662                 :        346 :   free (frame);
     663                 :            : }
     664                 :            : 
     665                 :            : static bool
     666                 :        192 : setfunc (int firstreg, unsigned nregs, const Dwarf_Word *regs, void *arg)
     667                 :            : {
     668                 :        192 :   Dwfl_Frame *state = arg;
     669                 :        192 :   Dwfl_Frame *unwound = state->unwound;
     670         [ +  + ]:        192 :   if (firstreg < 0)
     671                 :            :     {
     672         [ -  + ]:         60 :       assert (firstreg == -1);
     673         [ -  + ]:         60 :       assert (nregs == 1);
     674         [ -  + ]:         60 :       assert (unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
     675                 :         60 :       unwound->pc = *regs;
     676                 :         60 :       unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
     677                 :         60 :       return true;
     678                 :            :     }
     679         [ +  + ]:        274 :   while (nregs--)
     680         [ -  + ]:        142 :     if (! __libdwfl_frame_reg_set (unwound, firstreg++, *regs++))
     681                 :          0 :       return false;
     682                 :        132 :   return true;
     683                 :            : }
     684                 :            : 
     685                 :            : static bool
     686                 :        172 : getfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg)
     687                 :            : {
     688                 :        172 :   Dwfl_Frame *state = arg;
     689         [ -  + ]:        172 :   assert (firstreg >= 0);
     690         [ +  + ]:        362 :   while (nregs--)
     691         [ -  + ]:        190 :     if (INTUSE (dwfl_frame_reg) (state, firstreg++, regs++) != 0)
     692                 :          0 :       return false;
     693                 :        172 :   return true;
     694                 :            : }
     695                 :            : 
     696                 :            : static bool
     697                 :        132 : readfunc (Dwarf_Addr addr, Dwarf_Word *datap, void *arg)
     698                 :            : {
     699                 :        132 :   Dwfl_Frame *state = arg;
     700                 :        132 :   Dwfl_Thread *thread = state->thread;
     701                 :        132 :   Dwfl_Process *process = thread->process;
     702                 :        132 :   return process->callbacks->memory_read (process->dwfl, addr, datap,
     703                 :            :                                           process->callbacks_arg);
     704                 :            : }
     705                 :            : 
     706                 :            : void
     707                 :            : internal_function
     708                 :        770 : __libdwfl_frame_unwind (Dwfl_Frame *state)
     709                 :            : {
     710         [ +  + ]:        770 :   if (state->unwound)
     711                 :        714 :     return;
     712                 :            :   /* Do not ask dwfl_frame_pc for ISACTIVATION, it would try to unwind STATE
     713                 :            :      which would deadlock us.  */
     714                 :            :   Dwarf_Addr pc;
     715                 :        470 :   bool ok = INTUSE(dwfl_frame_pc) (state, &pc, NULL);
     716         [ -  + ]:        470 :   if (!ok)
     717                 :          0 :     return;
     718                 :            :   /* Check whether this is the initial frame or a signal frame.
     719                 :            :      Then we need to unwind from the original, unadjusted PC.  */
     720   [ +  +  +  - ]:        470 :   if (! state->initial_frame && ! state->signal_frame)
     721                 :        384 :     pc--;
     722                 :        470 :   Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc);
     723         [ +  + ]:        470 :   if (mod == NULL)
     724                 :          2 :     __libdwfl_seterrno (DWFL_E_NO_DWARF);
     725                 :            :   else
     726                 :            :     {
     727                 :            :       Dwarf_Addr bias;
     728                 :        468 :       Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (mod, &bias);
     729         [ +  + ]:        468 :       if (cfi_eh)
     730                 :            :         {
     731                 :        448 :           handle_cfi (state, pc - bias, cfi_eh, bias);
     732         [ +  + ]:        448 :           if (state->unwound)
     733                 :        346 :             return;
     734                 :            :         }
     735                 :        156 :       Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias);
     736         [ +  + ]:        156 :       if (cfi_dwarf)
     737                 :            :         {
     738                 :         72 :           handle_cfi (state, pc - bias, cfi_dwarf, bias);
     739         [ +  + ]:         72 :           if (state->unwound)
     740                 :         34 :             return;
     741                 :            :         }
     742                 :            :     }
     743         [ -  + ]:        124 :   assert (state->unwound == NULL);
     744                 :        124 :   Dwfl_Thread *thread = state->thread;
     745                 :        124 :   Dwfl_Process *process = thread->process;
     746                 :        124 :   Ebl *ebl = process->ebl;
     747         [ -  + ]:        124 :   if (new_unwound (state) == NULL)
     748                 :            :     {
     749                 :          0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     750                 :          0 :       return;
     751                 :            :     }
     752                 :        124 :   state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     753                 :            :   // &Dwfl_Frame.signal_frame cannot be passed as it is a bitfield.
     754                 :        124 :   bool signal_frame = false;
     755         [ +  + ]:        124 :   if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame))
     756                 :            :     {
     757                 :            :       // Discard the unwind attempt.  During next __libdwfl_frame_unwind call
     758                 :            :       // we may have for example the appropriate Dwfl_Module already mapped.
     759         [ -  + ]:         68 :       assert (state->unwound->unwound == NULL);
     760                 :         68 :       free (state->unwound);
     761                 :         68 :       state->unwound = NULL;
     762                 :            :       // __libdwfl_seterrno has been called above.
     763                 :         68 :       return;
     764                 :            :     }
     765         [ -  + ]:         56 :   assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET);
     766                 :         56 :   state->unwound->signal_frame = signal_frame;
     767                 :            : }

Generated by: LCOV version 1.14