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