Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libdw / encoded-value.h
1 /* DW_EH_PE_* support for libdw unwinder.
2    Copyright (C) 2009-2010 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 #ifndef _ENCODED_VALUE_H
30 #define _ENCODED_VALUE_H 1
31
32 #include <dwarf.h>
33 #include <stdlib.h>
34 #include "libdwP.h"
35
36
37 static size_t __attribute__ ((unused))
38 encoded_value_size (const Elf_Data *data, const unsigned char e_ident[],
39                     uint8_t encoding, const uint8_t *p)
40 {
41   if (encoding == DW_EH_PE_omit)
42     return 0;
43
44   switch (encoding & 0x07)
45     {
46     case DW_EH_PE_udata2:
47       return 2;
48     case DW_EH_PE_udata4:
49       return 4;
50     case DW_EH_PE_udata8:
51       return 8;
52
53     case DW_EH_PE_absptr:
54       return e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
55
56     case DW_EH_PE_uleb128:
57       if (p != NULL)
58         {
59           const uint8_t *end = p;
60           while (end < (uint8_t *) data->d_buf + data->d_size)
61             if (*end++ & 0x80u)
62               return end - p;
63         }
64
65     default:
66       abort ();
67       return 0;
68     }
69 }
70
71 static inline int __attribute__ ((unused))
72 __libdw_cfi_read_address_inc (const Dwarf_CFI *cache,
73                               const unsigned char **addrp,
74                               int width, Dwarf_Addr *ret)
75 {
76   width = width ?: cache->e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
77
78   if (cache->dbg != NULL)
79     return __libdw_read_address_inc (cache->dbg, IDX_debug_frame,
80                                      addrp, width, ret);
81
82   /* Only .debug_frame might have relocation to consider.
83      Read plain values from .eh_frame data.  */
84
85   if (width == 4)
86     *ret = read_4ubyte_unaligned_inc (cache, *addrp);
87   else
88     *ret = read_8ubyte_unaligned_inc (cache, *addrp);
89   return 0;
90 }
91
92 static bool __attribute__ ((unused))
93 read_encoded_value (const Dwarf_CFI *cache, uint8_t encoding, const uint8_t **p,
94                     Dwarf_Addr *result)
95 {
96   *result = 0;
97   switch (encoding & 0x70)
98     {
99     case DW_EH_PE_absptr:
100       break;
101     case DW_EH_PE_pcrel:
102       *result = (cache->frame_vaddr
103                  + (*p - (const uint8_t *) cache->data->d.d_buf));
104       break;
105     case DW_EH_PE_textrel:
106       // ia64: segrel
107       *result = cache->textrel;
108       break;
109     case DW_EH_PE_datarel:
110       // i386: GOTOFF
111       // ia64: gprel
112       *result = cache->datarel;
113       break;
114     case DW_EH_PE_funcrel:      /* XXX */
115       break;
116     case DW_EH_PE_aligned:
117       {
118         const size_t size = encoded_value_size (&cache->data->d, cache->e_ident,
119                                                 encoding, *p);
120         size_t align = ((cache->frame_vaddr
121                          + (*p - (const uint8_t *) cache->data->d.d_buf))
122                         & (size - 1));
123         if (align != 0)
124           *p += size - align;
125         break;
126       }
127
128     default:
129       abort ();
130     }
131
132   Dwarf_Addr value;
133   switch (encoding & 0x0f)
134     {
135     case DW_EH_PE_udata2:
136       value = read_2ubyte_unaligned_inc (cache, *p);
137       break;
138
139     case DW_EH_PE_sdata2:
140       value = read_2sbyte_unaligned_inc (cache, *p);
141       break;
142
143     case DW_EH_PE_udata4:
144       if (__libdw_cfi_read_address_inc (cache, p, 4, &value))
145         return true;
146       break;
147
148     case DW_EH_PE_sdata4:
149       if (__libdw_cfi_read_address_inc (cache, p, 4, &value))
150         return true;
151       value = (Dwarf_Sword) (Elf32_Sword) value; /* Sign-extend.  */
152       break;
153
154     case DW_EH_PE_udata8:
155     case DW_EH_PE_sdata8:
156       if (__libdw_cfi_read_address_inc (cache, p, 8, &value))
157         return true;
158       break;
159
160     case DW_EH_PE_absptr:
161       if (__libdw_cfi_read_address_inc (cache, p, 0, &value))
162         return true;
163       break;
164
165     case DW_EH_PE_uleb128:
166       get_uleb128 (value, *p);
167       break;
168
169     case DW_EH_PE_sleb128:
170       get_sleb128 (value, *p);
171       break;
172
173     default:
174       abort ();
175     }
176
177   *result += value;
178
179   if (encoding & DW_EH_PE_indirect)
180     {
181       if (unlikely (*result < cache->frame_vaddr))
182         return true;
183       *result -= cache->frame_vaddr;
184       if (unlikely (*result > (cache->data->d.d_size
185                                - encoded_value_size (NULL, cache->e_ident,
186                                                      DW_EH_PE_absptr, NULL))))
187         return true;
188       const uint8_t *ptr = cache->data->d.d_buf + *result;
189       return __libdw_cfi_read_address_inc (cache, &ptr, 0, result);
190     }
191
192   return false;
193 }
194
195 #endif  /* encoded-value.h */