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 : 23522 : 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 [ + - ]: 23522 : if (fs == NULL)
42 : : return -1;
43 : :
44 [ - + ]: 23522 : if (unlikely (regno < 0))
45 : : {
46 : 0 : __libdw_seterrno (DWARF_E_INVALID_ACCESS);
47 : 0 : return -1;
48 : : }
49 : :
50 : 23522 : *ops = ops_mem;
51 : 23522 : *nops = 0;
52 : :
53 [ + + ]: 23522 : if (unlikely ((size_t) regno >= fs->nregs))
54 : 9316 : goto default_rule;
55 : :
56 : 14206 : const struct dwarf_frame_register *reg = &fs->regs[regno];
57 : :
58 [ + + + + : 14206 : switch (reg->rule)
+ + ]
59 : : {
60 : : case reg_unspecified:
61 : 17018 : default_rule:
62 : : /* Use the default rule for registers not yet mentioned in CFI. */
63 [ - + ]: 17018 : 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 : 4644 : same_value:
72 : : /* The location is not known here, but the caller might know it. */
73 : 4644 : *ops = NULL;
74 : 4644 : break;
75 : :
76 : 1682 : case reg_offset:
77 : : case reg_val_offset:
78 : 1682 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa };
79 [ + + ]: 1682 : if (reg->value != 0)
80 : 1330 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_plus_uconst,
81 : 1330 : .number = reg->value };
82 [ + + ]: 1682 : if (reg->rule == reg_val_offset)
83 : : /* A value, not a location. */
84 : 334 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_stack_value };
85 : 1682 : *ops = ops_mem;
86 : 1682 : 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 : mutex_lock (fs->cache->lock);
113 : 4 : int res = __libdw_intern_expression (NULL,
114 : 2 : fs->cache->other_byte_order,
115 : : address_size, 4,
116 : : &fs->cache->expr_tree, &block,
117 : 2 : true, reg->rule == reg_val_expression,
118 : : ops, nops, IDX_debug_frame);
119 : 2 : mutex_unlock (fs->cache->lock);
120 : :
121 [ - + ]: 2 : if (res < 0)
122 : : return -1;
123 : 2 : break;
124 : : }
125 : : }
126 : :
127 : : return 0;
128 : : }
|