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 : 10257 : 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 [ + - ]: 10257 : if (fs == NULL)
42 : : return -1;
43 : :
44 [ - + ]: 10257 : if (unlikely (regno < 0))
45 : : {
46 : 0 : __libdw_seterrno (DWARF_E_INVALID_ACCESS);
47 : 0 : return -1;
48 : : }
49 : :
50 : 10257 : *ops = ops_mem;
51 : 10257 : *nops = 0;
52 : :
53 [ + + ]: 10257 : if (unlikely ((size_t) regno >= fs->nregs))
54 : : goto default_rule;
55 : :
56 : 5905 : const struct dwarf_frame_register *reg = &fs->regs[regno];
57 : :
58 [ + + + + : 5905 : switch (reg->rule)
+ + ]
59 : : {
60 : : case reg_unspecified:
61 : 7213 : default_rule:
62 : : /* Use the default rule for registers not yet mentioned in CFI. */
63 [ - + ]: 7213 : if (fs->cache->default_same_value)
64 : : 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 : 2109 : same_value:
72 : : /* The location is not known here, but the caller might know it. */
73 : 2109 : *ops = NULL;
74 : 2109 : break;
75 : :
76 : 834 : case reg_offset:
77 : : case reg_val_offset:
78 : 834 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa };
79 [ + + ]: 834 : if (reg->value != 0)
80 : 1298 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_plus_uconst,
81 : 649 : .number = reg->value };
82 [ + + ]: 834 : if (reg->rule == reg_val_offset)
83 : : /* A value, not a location. */
84 : 176 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_stack_value };
85 : 834 : *ops = ops_mem;
86 : 834 : break;
87 : :
88 : 73 : case reg_register:
89 : 146 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_regx,
90 : 73 : .number = reg->value };
91 : 73 : break;
92 : :
93 : 9 : case reg_val_expression:
94 : : case reg_expression:
95 : : {
96 : 18 : unsigned int address_size = (fs->cache->e_ident[EI_CLASS] == ELFCLASS32
97 [ + + ]: 9 : ? 4 : 8);
98 : :
99 : 9 : Dwarf_Block block;
100 : 9 : const uint8_t *p = fs->cache->data->d.d_buf + reg->value;
101 : 18 : const uint8_t *end = (fs->cache->data->d.d_buf
102 : 9 : + fs->cache->data->d.d_size);
103 : 9 : get_uleb128 (block.length, p, end);
104 : 9 : block.data = (void *) p;
105 : :
106 : : /* Parse the expression into internal form. */
107 [ - + ]: 9 : if (__libdw_intern_expression (NULL,
108 : 9 : fs->cache->other_byte_order,
109 : : address_size, 4,
110 : 9 : &fs->cache->expr_tree, &block,
111 : 9 : true, reg->rule == reg_val_expression,
112 : : ops, nops, IDX_debug_frame) < 0)
113 : 0 : return -1;
114 : 9 : break;
115 : : }
116 : : }
117 : :
118 : : return 0;
119 : : }
|