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 10205 : 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 10205 : if (fs == NULL)
42 : return -1;
43 :
44 10205 : if (unlikely (regno < 0))
45 : {
46 0 : __libdw_seterrno (DWARF_E_INVALID_ACCESS);
47 0 : return -1;
48 : }
49 :
50 10205 : *ops = ops_mem;
51 10205 : *nops = 0;
52 :
53 10205 : if (unlikely ((size_t) regno >= fs->nregs))
54 : goto default_rule;
55 :
56 5869 : const struct dwarf_frame_register *reg = &fs->regs[regno];
57 :
58 5869 : switch (reg->rule)
59 : {
60 : case reg_unspecified:
61 11519 : default_rule:
62 : /* Use the default rule for registers not yet mentioned in CFI. */
63 7183 : 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 0 : same_value:
72 : /* The location is not known here, but the caller might know it. */
73 2091 : *ops = NULL;
74 2091 : break;
75 :
76 832 : case reg_offset:
77 : case reg_val_offset:
78 832 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_call_frame_cfa };
79 832 : if (reg->value != 0)
80 1300 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_plus_uconst,
81 650 : .number = reg->value };
82 832 : if (reg->rule == reg_val_offset)
83 : /* A value, not a location. */
84 173 : ops_mem[(*nops)++] = (Dwarf_Op) { .atom = DW_OP_stack_value };
85 832 : *ops = ops_mem;
86 832 : 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 : Dwarf_Block block;
100 9 : const uint8_t *p = fs->cache->data->d.d_buf + reg->value;
101 9 : 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 27 : 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 : }
|