LCOV - code coverage report
Current view: top level - libdwfl - frame_unwind.c (source / functions) Coverage Total Hit
Test: elfutils-0.192 Lines: 70.7 % 389 275
Test Date: 2024-10-18 15:14:37 Functions: 100.0 % 12 12
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 59.4 % 404 240

             Branch data     Line data    Source code
       1                 :             : /* Get previous frame state for an existing frame state.
       2                 :             :    Copyright (C) 2013, 2014, 2016, 2024 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                 :        7776 : __libdwfl_frame_reg_get (Dwfl_Frame *state, unsigned regno, Dwarf_Addr *val)
      49                 :             : {
      50                 :        7776 :   Ebl *ebl = state->thread->process->ebl;
      51         [ +  + ]:        7776 :   if (! ebl_dwarf_to_regno (ebl, &regno))
      52                 :             :     return -1;
      53         [ +  - ]:        7760 :   if (regno >= ebl_frame_nregs (ebl))
      54                 :             :     return -1;
      55                 :        7760 :   if ((state->regs_set[regno / sizeof (*state->regs_set) / 8]
      56         [ +  + ]:        7760 :        & ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)))) == 0)
      57                 :             :     return 1;
      58         [ +  - ]:        4226 :   if (val)
      59                 :        4226 :     *val = state->regs[regno];
      60                 :             :   return 0;
      61                 :             : }
      62                 :             : 
      63                 :             : bool
      64                 :             : internal_function
      65                 :        5656 : __libdwfl_frame_reg_set (Dwfl_Frame *state, unsigned regno, Dwarf_Addr val)
      66                 :             : {
      67                 :        5656 :   Ebl *ebl = state->thread->process->ebl;
      68         [ +  + ]:        5656 :   if (! ebl_dwarf_to_regno (ebl, &regno))
      69                 :             :     return false;
      70         [ +  - ]:        5640 :   if (regno >= ebl_frame_nregs (ebl))
      71                 :             :     return false;
      72                 :             :   /* For example i386 user_regs_struct has signed fields.  */
      73         [ +  + ]:        5640 :   if (ebl_get_elfclass (ebl) == ELFCLASS32)
      74                 :        1402 :     val &= 0xffffffff;
      75                 :        5640 :   state->regs_set[regno / sizeof (*state->regs_set) / 8] |=
      76                 :        5640 :                 ((uint64_t) 1U << (regno % (sizeof (*state->regs_set) * 8)));
      77                 :        5640 :   state->regs[regno] = val;
      78                 :        5640 :   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                 :        5020 : do_push (struct eval_stack *stack, Dwarf_Addr val)
      97                 :             : {
      98         [ -  + ]:        5020 :   if (stack->used >= DWARF_EXPR_STACK_MAX)
      99                 :             :     {
     100                 :           0 :       __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     101                 :           0 :       return false;
     102                 :             :     }
     103         [ +  + ]:        5020 :   if (stack->used == stack->allocated)
     104                 :             :     {
     105                 :        3216 :       stack->allocated = MAX (stack->allocated * 2, 32);
     106                 :        3216 :       Dwarf_Addr *new_addrs;
     107                 :        3216 :       new_addrs = realloc (stack->addrs,
     108                 :             :                            stack->allocated * sizeof (*stack->addrs));
     109         [ -  + ]:        3216 :       if (new_addrs == NULL)
     110                 :             :         {
     111                 :           0 :           __libdwfl_seterrno (DWFL_E_NOMEM);
     112                 :           0 :           return false;
     113                 :             :         }
     114                 :        3216 :       stack->addrs = new_addrs;
     115                 :             :     }
     116                 :        5020 :   stack->addrs[stack->used++] = val;
     117                 :        5020 :   return true;
     118                 :             : }
     119                 :             : 
     120                 :             : static bool
     121                 :        5020 : do_pop (struct eval_stack *stack, Dwarf_Addr *val)
     122                 :             : {
     123         [ -  + ]:        5020 :   if (stack->used == 0)
     124                 :             :     {
     125                 :           0 :       __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     126                 :           0 :       return false;
     127                 :             :     }
     128                 :        5020 :   *val = stack->addrs[--stack->used];
     129                 :        5020 :   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                 :        3236 : expr_eval (Dwfl_Frame *state, Dwarf_Frame *frame, const Dwarf_Op *ops,
     137                 :             :            size_t nops, Dwarf_Addr *result, Dwarf_Addr bias)
     138                 :             : {
     139                 :        3236 :   Dwfl_Process *process = state->thread->process;
     140         [ -  + ]:        3236 :   if (nops == 0)
     141                 :             :     {
     142                 :           0 :       __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     143                 :           0 :       return false;
     144                 :             :     }
     145                 :        3236 :   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                 :        3236 :   Dwarf_Addr val1, val2;
     156                 :        3236 :   bool is_location = false;
     157                 :        3236 :   size_t steps_count = 0;
     158         [ +  + ]:        8630 :   for (const Dwarf_Op *op = ops; op < ops + nops; op++)
     159                 :             :     {
     160         [ -  + ]:        5414 :       if (++steps_count > DWARF_EXPR_STEPS_MAX)
     161                 :             :         {
     162                 :           0 :           __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     163                 :           0 :           return false;
     164                 :             :         }
     165   [ +  -  -  +  :        5414 :       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                 :        5394 :           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                 :             :           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                 :             :           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                 :             :           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                 :             :           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                 :             :           break;
     230                 :        1546 :         case DW_OP_bregx:
     231         [ +  + ]:        1546 :           if (INTUSE (dwfl_frame_reg) (state, op->number, &val1) != 0)
     232                 :             :             {
     233                 :          10 :               free (stack.addrs);
     234                 :          10 :               return false;
     235                 :             :             }
     236                 :        1536 :           val1 += op->number2;
     237         [ -  + ]:        1536 :           if (! push (val1))
     238                 :             :             {
     239                 :           0 :               free (stack.addrs);
     240                 :           0 :               return false;
     241                 :             :             }
     242                 :             :           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                 :             :           break;
     250                 :           2 :         case DW_OP_drop:
     251         [ -  + ]:           2 :           if (! pop (&val1))
     252                 :             :             {
     253                 :           0 :               free (stack.addrs);
     254                 :           0 :               return false;
     255                 :             :             }
     256                 :             :           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                 :             :           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                 :             :           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                 :             :           break;
     285                 :           2 :         case DW_OP_rot:
     286                 :             :           {
     287                 :           2 :             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                 :             :           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                 :        1240 :         case DW_OP_plus_uconst:
     350   [ +  -  -  + ]:        1240 :           if (! pop (&val1) || ! push (val1 + op->number))
     351                 :             :             {
     352                 :           0 :               free (stack.addrs);
     353                 :           0 :               return false;
     354                 :             :             }
     355                 :             :           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                 :             :           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                 :             :           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                 :             :             break;
     434                 :         122 :           FALLTHROUGH;
     435                 :         122 :         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                 :             :         case DW_OP_nop:
     450                 :             :           break;
     451                 :             :         /* DW_OP_* not listed in libgcc/unwind-dw2.c execute_stack_op:  */
     452                 :        1546 :         case DW_OP_call_frame_cfa:;
     453                 :             :           // Not used by CFI itself but it is synthetized by elfutils internation.
     454                 :        1546 :           Dwarf_Op *cfa_ops;
     455                 :        1546 :           size_t cfa_nops;
     456                 :        1546 :           Dwarf_Addr cfa;
     457         [ +  - ]:        1546 :           if (frame == NULL
     458         [ +  - ]:        1546 :               || dwarf_frame_cfa (frame, &cfa_ops, &cfa_nops) != 0
     459         [ +  + ]:        1546 :               || ! expr_eval (state, NULL, cfa_ops, cfa_nops, &cfa, bias)
     460         [ -  + ]:        1536 :               || ! push (cfa))
     461                 :             :             {
     462                 :          10 :               __libdwfl_seterrno (DWFL_E_LIBDW);
     463                 :          10 :               free (stack.addrs);
     464                 :          10 :               return false;
     465                 :             :             }
     466                 :             :           is_location = true;
     467                 :             :           break;
     468                 :         282 :         case DW_OP_stack_value:
     469                 :             :           // Not used by CFI itself but it is synthetized by elfutils internation.
     470                 :         282 :           is_location = false;
     471                 :         282 :           break;
     472                 :           0 :         default:
     473                 :           0 :           __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     474                 :           0 :           return false;
     475                 :             :       }
     476                 :             :     }
     477         [ -  + ]:        3216 :   if (! pop (result))
     478                 :             :     {
     479                 :           0 :       free (stack.addrs);
     480                 :           0 :       return false;
     481                 :             :     }
     482                 :        3216 :   free (stack.addrs);
     483         [ +  + ]:        3216 :   if (is_location)
     484                 :             :     {
     485         [ -  + ]:        1254 :       if (process->callbacks->memory_read == NULL)
     486                 :             :         {
     487                 :           0 :           __libdwfl_seterrno (DWFL_E_INVALID_ARGUMENT);
     488                 :           0 :           return false;
     489                 :             :         }
     490         [ +  + ]:        1254 :       if (! process->callbacks->memory_read (process->dwfl, *result, result,
     491                 :             :                                              process->callbacks_arg))
     492                 :          12 :         return false;
     493                 :             :     }
     494                 :             :   return true;
     495                 :             : #undef push
     496                 :             : #undef pop
     497                 :             : }
     498                 :             : 
     499                 :             : static Dwfl_Frame *
     500                 :         466 : new_unwound (Dwfl_Frame *state)
     501                 :             : {
     502         [ -  + ]:         466 :   assert (state->unwound == NULL);
     503                 :         466 :   Dwfl_Thread *thread = state->thread;
     504                 :         466 :   Dwfl_Process *process = thread->process;
     505                 :         466 :   Ebl *ebl = process->ebl;
     506                 :         466 :   size_t nregs = ebl_frame_nregs (ebl);
     507         [ -  + ]:         466 :   assert (nregs > 0);
     508                 :         466 :   Dwfl_Frame *unwound;
     509                 :         466 :   unwound = malloc (sizeof (*unwound) + sizeof (*unwound->regs) * nregs);
     510         [ +  - ]:         466 :   if (unlikely (unwound == NULL))
     511                 :             :     return NULL;
     512                 :         466 :   state->unwound = unwound;
     513                 :         466 :   unwound->thread = thread;
     514                 :         466 :   unwound->unwound = NULL;
     515                 :         466 :   unwound->signal_frame = false;
     516                 :         466 :   unwound->initial_frame = false;
     517                 :         466 :   unwound->pc_state = DWFL_FRAME_STATE_ERROR;
     518                 :         466 :   unwound->unwound_source = DWFL_UNWOUND_NONE;
     519                 :         466 :   memset (unwound->regs_set, 0, sizeof (unwound->regs_set));
     520                 :         466 :   return unwound;
     521                 :             : }
     522                 :             : 
     523                 :             : /* The logic is to call __libdwfl_seterrno for any CFI bytecode interpretation
     524                 :             :    error so one can easily catch the problem with a debugger.  Still there are
     525                 :             :    archs with invalid CFI for some registers where the registers are never used
     526                 :             :    later.  Therefore we continue unwinding leaving the registers undefined.  */
     527                 :             : 
     528                 :             : static void
     529                 :         512 : handle_cfi (Dwfl_Frame *state, Dwarf_Addr pc, Dwarf_CFI *cfi, Dwarf_Addr bias)
     530                 :             : {
     531                 :         512 :   Dwarf_Frame *frame;
     532         [ +  + ]:         512 :   if (INTUSE(dwarf_cfi_addrframe) (cfi, pc, &frame) != 0)
     533                 :             :     {
     534                 :         174 :       __libdwfl_seterrno (DWFL_E_LIBDW);
     535                 :         348 :       return;
     536                 :             :     }
     537                 :             : 
     538                 :         338 :   Dwfl_Frame *unwound = new_unwound (state);
     539         [ -  + ]:         338 :   if (unwound == NULL)
     540                 :             :     {
     541                 :           0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     542                 :           0 :       return;
     543                 :             :     }
     544                 :             : 
     545                 :         338 :   unwound->signal_frame = frame->fde->cie->signal_frame;
     546                 :         338 :   Dwfl_Thread *thread = state->thread;
     547                 :         338 :   Dwfl_Process *process = thread->process;
     548                 :         338 :   Ebl *ebl = process->ebl;
     549                 :         338 :   size_t nregs = ebl_frame_nregs (ebl);
     550         [ -  + ]:         338 :   assert (nregs > 0);
     551                 :             : 
     552                 :             :   /* The return register is special for setting the unwound->pc_state.  */
     553                 :         338 :   unsigned ra = frame->fde->cie->return_address_register;
     554                 :         338 :   bool ra_set = false;
     555         [ -  + ]:         338 :   if (! ebl_dwarf_to_regno (ebl, &ra))
     556                 :             :     {
     557                 :           0 :       __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
     558                 :           0 :       return;
     559                 :             :     }
     560                 :             : 
     561         [ +  + ]:       14716 :   for (unsigned regno = 0; regno < nregs; regno++)
     562                 :             :     {
     563                 :       14378 :       Dwarf_Op reg_ops_mem[3], *reg_ops;
     564                 :       14378 :       size_t reg_nops;
     565         [ -  + ]:       14378 :       if (dwarf_frame_register (frame, regno, reg_ops_mem, &reg_ops,
     566                 :             :                                 &reg_nops) != 0)
     567                 :             :         {
     568                 :           0 :           __libdwfl_seterrno (DWFL_E_LIBDW);
     569                 :       10664 :           continue;
     570                 :             :         }
     571                 :       14378 :       Dwarf_Addr regval;
     572         [ +  + ]:       14378 :       if (reg_nops == 0)
     573                 :             :         {
     574         [ +  + ]:       12688 :           if (reg_ops == reg_ops_mem)
     575                 :             :             {
     576                 :             :               /* REGNO is undefined.  */
     577         [ +  + ]:        8736 :               if (regno == ra)
     578                 :          28 :                 unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     579                 :        8736 :               continue;
     580                 :             :             }
     581         [ +  - ]:        3952 :           else if (reg_ops == NULL)
     582                 :             :             {
     583                 :             :               /* REGNO is same-value.  */
     584         [ +  + ]:        3952 :               if (INTUSE (dwfl_frame_reg) (state, regno, &regval) != 0)
     585                 :        1906 :                 continue;
     586                 :             :             }
     587                 :             :           else
     588                 :             :             {
     589                 :           0 :               __libdwfl_seterrno (DWFL_E_INVALID_DWARF);
     590                 :           0 :               continue;
     591                 :             :             }
     592                 :             :         }
     593         [ +  + ]:        1690 :       else if (! expr_eval (state, frame, reg_ops, reg_nops, &regval, bias))
     594                 :             :         {
     595                 :             :           /* PPC32 vDSO has various invalid operations, ignore them.  The
     596                 :             :              register will look as unset causing an error later, if used.
     597                 :             :              But PPC32 does not use such registers.  */
     598                 :          22 :           continue;
     599                 :             :         }
     600                 :             : 
     601                 :             :       /* Some architectures encode some extra info in the return address.  */
     602         [ +  + ]:        3714 :       if (regno == frame->fde->cie->return_address_register)
     603                 :             :         {
     604                 :         306 :           regval &= ebl_func_addr_mask (ebl);
     605                 :             : 
     606                 :             :           /* In aarch64, pseudo-register RA_SIGN_STATE indicates whether the
     607                 :             :              return address needs demangling using the PAC mask from the
     608                 :             :              thread. */
     609         [ +  + ]:         306 :           if (cfi->e_machine == EM_AARCH64 &&
     610         [ +  - ]:          38 :               frame->nregs > DW_AARCH64_RA_SIGN_STATE &&
     611         [ +  + ]:          38 :               frame->regs[DW_AARCH64_RA_SIGN_STATE].value & 0x1)
     612                 :             :             {
     613                 :          14 :               regval &= ~(state->thread->aarch64.pauth_insn_mask);
     614                 :             :             }
     615                 :             :         }
     616                 :             : 
     617                 :             :       /* This is another strange PPC[64] case.  There are two
     618                 :             :          registers numbers that can represent the same DWARF return
     619                 :             :          register number.  We only want one to actually set the return
     620                 :             :          register value.  But we always want to override the value if
     621                 :             :          the register is the actual CIE return address register.  */
     622   [ +  +  +  - ]:        3714 :       if (ra_set && regno != frame->fde->cie->return_address_register)
     623                 :             :         {
     624                 :         434 :           unsigned r = regno;
     625   [ +  -  -  + ]:         434 :           if (ebl_dwarf_to_regno (ebl, &r) && r == ra)
     626                 :           0 :             continue;
     627                 :             :         }
     628                 :             : 
     629         [ -  + ]:        3714 :       if (! __libdwfl_frame_reg_set (unwound, regno, regval))
     630                 :             :         {
     631                 :           0 :           __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
     632                 :           0 :           continue;
     633                 :             :         }
     634         [ +  + ]:        3714 :       else if (! ra_set)
     635                 :             :         {
     636                 :        3280 :           unsigned r = regno;
     637   [ +  -  +  + ]:        3280 :           if (ebl_dwarf_to_regno (ebl, &r) && r == ra)
     638                 :         306 :             ra_set = true;
     639                 :             :         }
     640                 :             :     }
     641         [ +  + ]:         338 :   if (unwound->pc_state == DWFL_FRAME_STATE_ERROR)
     642                 :             :     {
     643                 :         620 :       int res = INTUSE (dwfl_frame_reg) (unwound,
     644                 :         310 :           frame->fde->cie->return_address_register,
     645                 :         310 :           &unwound->pc);
     646         [ +  + ]:         310 :       if (res == 0)
     647                 :             :         {
     648                 :             :           /* PPC32 __libc_start_main properly CFI-unwinds PC as zero.
     649                 :             :              Currently none of the archs supported for unwinding have
     650                 :             :              zero as a valid PC.  */
     651         [ +  + ]:         306 :           if (unwound->pc == 0)
     652                 :           2 :             unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     653                 :             :           else
     654                 :             :             {
     655                 :         304 :               unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
     656                 :             :               /* In SPARC the return address register actually contains
     657                 :             :                  the address of the call instruction instead of the return
     658                 :             :                  address.  Therefore we add here an offset defined by the
     659                 :             :                  backend.  Most likely 0.  */
     660                 :         304 :               unwound->pc += ebl_ra_offset (ebl);
     661                 :             :             }
     662                 :             :         }
     663                 :             :       else
     664                 :             :         {
     665                 :             :           /* We couldn't set the return register, either it was bogus,
     666                 :             :              or the return pc is undefined, maybe end of call stack.  */
     667                 :           4 :           unsigned pcreg = frame->fde->cie->return_address_register;
     668         [ +  - ]:           4 :           if (! ebl_dwarf_to_regno (ebl, &pcreg)
     669         [ -  + ]:           4 :               || pcreg >= ebl_frame_nregs (ebl))
     670                 :           0 :             __libdwfl_seterrno (DWFL_E_INVALID_REGISTER);
     671                 :             :           else
     672                 :           4 :             unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     673                 :             :         }
     674                 :             :     }
     675                 :         338 :   free (frame);
     676                 :             : }
     677                 :             : 
     678                 :             : static bool
     679                 :         192 : setfunc (int firstreg, unsigned nregs, const Dwarf_Word *regs, void *arg)
     680                 :             : {
     681                 :         192 :   Dwfl_Frame *state = arg;
     682                 :         192 :   Dwfl_Frame *unwound = state->unwound;
     683         [ +  + ]:         192 :   if (firstreg < 0)
     684                 :             :     {
     685         [ -  + ]:          60 :       assert (firstreg == -1);
     686         [ -  + ]:          60 :       assert (nregs == 1);
     687         [ -  + ]:          60 :       assert (unwound->pc_state == DWFL_FRAME_STATE_PC_UNDEFINED);
     688                 :          60 :       unwound->pc = *regs;
     689                 :          60 :       unwound->pc_state = DWFL_FRAME_STATE_PC_SET;
     690                 :          60 :       return true;
     691                 :             :     }
     692         [ +  + ]:         274 :   while (nregs--)
     693         [ +  - ]:         142 :     if (! __libdwfl_frame_reg_set (unwound, firstreg++, *regs++))
     694                 :             :       return false;
     695                 :             :   return true;
     696                 :             : }
     697                 :             : 
     698                 :             : static bool
     699                 :         176 : getfunc (int firstreg, unsigned nregs, Dwarf_Word *regs, void *arg)
     700                 :             : {
     701                 :         176 :   Dwfl_Frame *state = arg;
     702         [ -  + ]:         176 :   assert (firstreg >= 0);
     703         [ +  + ]:         370 :   while (nregs--)
     704         [ +  - ]:         194 :     if (INTUSE (dwfl_frame_reg) (state, firstreg++, regs++) != 0)
     705                 :             :       return false;
     706                 :             :   return true;
     707                 :             : }
     708                 :             : 
     709                 :             : static bool
     710                 :         132 : readfunc (Dwarf_Addr addr, Dwarf_Word *datap, void *arg)
     711                 :             : {
     712                 :         132 :   Dwfl_Frame *state = arg;
     713                 :         132 :   Dwfl_Thread *thread = state->thread;
     714                 :         132 :   Dwfl_Process *process = thread->process;
     715                 :         132 :   return process->callbacks->memory_read (process->dwfl, addr, datap,
     716                 :             :                                           process->callbacks_arg);
     717                 :             : }
     718                 :             : 
     719                 :             : void
     720                 :             : internal_function
     721                 :         758 : __libdwfl_frame_unwind (Dwfl_Frame *state)
     722                 :             : {
     723         [ +  + ]:         758 :   if (state->unwound)
     724                 :         702 :     return;
     725                 :             :   /* Do not ask dwfl_frame_pc for ISACTIVATION, it would try to unwind STATE
     726                 :             :      which would deadlock us.  */
     727                 :         466 :   Dwarf_Addr pc;
     728                 :         466 :   bool ok = INTUSE(dwfl_frame_pc) (state, &pc, NULL);
     729         [ +  - ]:         466 :   if (!ok)
     730                 :             :     return;
     731                 :             :   /* Check whether this is the initial frame or a signal frame.
     732                 :             :      Then we need to unwind from the original, unadjusted PC.  */
     733   [ +  +  +  - ]:         466 :   if (! state->initial_frame && ! state->signal_frame)
     734                 :         380 :     pc--;
     735                 :         466 :   Dwfl_Module *mod = INTUSE(dwfl_addrmodule) (state->thread->process->dwfl, pc);
     736         [ +  + ]:         466 :   if (mod == NULL)
     737                 :           2 :     __libdwfl_seterrno (DWFL_E_NO_DWARF);
     738                 :             :   else
     739                 :             :     {
     740                 :         464 :       Dwarf_Addr bias;
     741                 :         464 :       Dwarf_CFI *cfi_eh = INTUSE(dwfl_module_eh_cfi) (mod, &bias);
     742         [ +  + ]:         464 :       if (cfi_eh)
     743                 :             :         {
     744                 :         440 :           handle_cfi (state, pc - bias, cfi_eh, bias);
     745         [ +  + ]:         440 :           if (state->unwound)
     746                 :             :             {
     747                 :         304 :               state->unwound->unwound_source = DWFL_UNWOUND_EH_CFI;
     748                 :         338 :               return;
     749                 :             :             }
     750                 :             :         }
     751                 :         160 :       Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias);
     752         [ +  + ]:         160 :       if (cfi_dwarf)
     753                 :             :         {
     754                 :          72 :           handle_cfi (state, pc - bias, cfi_dwarf, bias);
     755         [ +  + ]:          72 :           if (state->unwound)
     756                 :             :             {
     757                 :          34 :               state->unwound->unwound_source = DWFL_UNWOUND_DWARF_CFI;
     758                 :          34 :               return;
     759                 :             :             }
     760                 :             :         }
     761                 :             :     }
     762         [ -  + ]:         128 :   assert (state->unwound == NULL);
     763                 :         128 :   Dwfl_Thread *thread = state->thread;
     764                 :         128 :   Dwfl_Process *process = thread->process;
     765                 :         128 :   Ebl *ebl = process->ebl;
     766         [ -  + ]:         128 :   if (new_unwound (state) == NULL)
     767                 :             :     {
     768                 :           0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
     769                 :           0 :       return;
     770                 :             :     }
     771                 :         128 :   state->unwound->pc_state = DWFL_FRAME_STATE_PC_UNDEFINED;
     772                 :             :   // &Dwfl_Frame.signal_frame cannot be passed as it is a bitfield.
     773                 :         128 :   bool signal_frame = false;
     774         [ +  + ]:         128 :   if (! ebl_unwind (ebl, pc, setfunc, getfunc, readfunc, state, &signal_frame))
     775                 :             :     {
     776                 :             :       // Discard the unwind attempt.  During next __libdwfl_frame_unwind call
     777                 :             :       // we may have for example the appropriate Dwfl_Module already mapped.
     778         [ -  + ]:          72 :       assert (state->unwound->unwound == NULL);
     779                 :          72 :       free (state->unwound);
     780                 :          72 :       state->unwound = NULL;
     781                 :             :       // __libdwfl_seterrno has been called above.
     782                 :          72 :       return;
     783                 :             :     }
     784                 :          56 :   state->unwound->unwound_source = DWFL_UNWOUND_EBL;
     785         [ -  + ]:          56 :   assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET);
     786                 :          56 :   state->unwound->signal_frame = signal_frame;
     787                 :             : }
        

Generated by: LCOV version 2.0-1