Branch data Line data Source code
1 : : /* Get register location expression for frame. 2 : : Copyright (C) 2009-2010, 2014 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 <dwarf.h> 35 : : 36 : : int 37 : 21674 : dwarf_frame_register (Dwarf_Frame *fs, int regno, Dwarf_Op ops_mem[3], 38 : : Dwarf_Op **ops, size_t *nops) 39 : : { 40 : : /* Maybe there was a previous error. */ 41 [ + - ]: 21674 : if (fs == NULL) 42 : : return -1; 43 : : 44 [ - + ]: 21674 : if (unlikely (regno < 0)) 45 : : { 46 : 0 : __libdw_seterrno (DWARF_E_INVALID_ACCESS); 47 : 0 : return -1; 48 : : } 49 : : 50 : 21674 : *ops = ops_mem; 51 : 21674 : *nops = 0; 52 : : 53 [ + + ]: 21674 : if (unlikely ((size_t) regno >= fs->nregs)) 54 : 9010 : goto default_rule; 55 : : 56 : 12664 : const struct dwarf_frame_register *reg = &fs->regs[regno]; 57 : : 58 [ + + + + : 12664 : switch (reg->rule) + + ] 59 : : { 60 : : case reg_unspecified: 61 : 15596 : default_rule: 62 : : /* Use the default rule for registers not yet mentioned in CFI. */ 63 [ - + ]: 15596 : if (fs->cache->default_same_value) 64 : 0 : goto same_value; 65 : : FALLTHROUGH; 66 : : case reg_undefined: 67 : : /* The value is known to be unavailable. */ 68 : : break; 69 : : 70 : : case reg_same_value: 71 : 4348 : same_value: 72 : : /* The location is not known here, but the caller might know it. */ 73 : 4348 : *ops = NULL; 74 : 4348 : break; 75 : : 76 : 1554 : case reg_offset: 77 : : case reg_val_offset: 78 : 1554 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa }; 79 [ + + ]: 1554 : if (reg->value != 0) 80 : 1226 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_plus_uconst, 81 : 1226 : .number = reg->value }; 82 [ + + ]: 1554 : if (reg->rule == reg_val_offset) 83 : : /* A value, not a location. */ 84 : 310 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_stack_value }; 85 : 1554 : *ops = ops_mem; 86 : 1554 : break; 87 : : 88 : 146 : case reg_register: 89 : 146 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_regx, 90 : 146 : .number = reg->value }; 91 : 146 : break; 92 : : 93 : 2 : case reg_val_expression: 94 : : case reg_expression: 95 : : { 96 : 4 : unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32 97 [ + - ]: 2 : ? 4 : 8); 98 : : 99 : 2 : Dwarf_Block block; 100 : 2 : const uint8_t *p = fs->cache->data->d.d_buf + reg->value; 101 : 2 : const uint8_t *end = (fs->cache->data->d.d_buf 102 : 2 : + fs->cache->data->d.d_size); 103 [ - + ]: 2 : if (p >= end) 104 : : { 105 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF); 106 : 0 : return -1; 107 : : } 108 : 2 : get_uleb128 (block.length, p, end); 109 : 2 : block.data = (void *) p; 110 : : 111 : : /* Parse the expression into internal form. */ 112 [ - + ]: 2 : if (__libdw_intern_expression (NULL, 113 : 2 : fs->cache->other_byte_order, 114 : : address_size, 4, 115 : : &fs->cache->expr_tree, &block, 116 : 2 : true, reg->rule == reg_val_expression, 117 : : ops, nops, IDX_debug_frame) < 0) 118 : : return -1; 119 : 2 : break; 120 : : } 121 : : } 122 : : 123 : : return 0; 124 : : }