1 /* Return address represented by attribute.
2 Copyright (C) 2003-2010, 2018 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 <dwarf.h>
34 #include "libdwP.h"
35
36
37 int
__libdw_addrx(Dwarf_CU * cu,Dwarf_Word idx,Dwarf_Addr * addr)38 __libdw_addrx (Dwarf_CU *cu, Dwarf_Word idx, Dwarf_Addr *addr)
39 {
40 Dwarf_Off addr_off = __libdw_cu_addr_base (cu);
41 if (addr_off == (Dwarf_Off) -1)
42 return -1;
43
44 Dwarf *dbg = cu->dbg;
45 if (dbg->sectiondata[IDX_debug_addr] == NULL)
46 {
47 __libdw_seterrno (DWARF_E_NO_DEBUG_ADDR);
48 return -1;
49 }
50
51 /* The section should at least contain room for one address. */
52 int address_size = cu->address_size;
53 if (cu->address_size > dbg->sectiondata[IDX_debug_addr]->d_size)
54 {
55 invalid_offset:
56 __libdw_seterrno (DWARF_E_INVALID_OFFSET);
57 return -1;
58 }
59
60 if (addr_off > (dbg->sectiondata[IDX_debug_addr]->d_size
61 - address_size))
62 goto invalid_offset;
63
64 idx *= address_size;
65 if (idx > (dbg->sectiondata[IDX_debug_addr]->d_size
66 - address_size - addr_off))
67 goto invalid_offset;
68
69 const unsigned char *datap;
70 datap = dbg->sectiondata[IDX_debug_addr]->d_buf + addr_off + idx;
71 if (address_size == 4)
72 *addr = read_4ubyte_unaligned (dbg, datap);
73 else
74 *addr = read_8ubyte_unaligned (dbg, datap);
75
76 return 0;
77 }
78
79 int
dwarf_formaddr(Dwarf_Attribute * attr,Dwarf_Addr * return_addr)80 dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
81 {
82 if (attr == NULL)
83 return -1;
84
85 Dwarf_Word idx;
86 Dwarf_CU *cu = attr->cu;
87 Dwarf *dbg = cu->dbg;
88 const unsigned char *datap = attr->valp;
89 const unsigned char *endp = attr->cu->endp;
90 switch (attr->form)
91 {
92 /* There is one form that just encodes the whole address. */
93 case DW_FORM_addr:
94 if (__libdw_read_address (dbg, cu_sec_idx (cu), datap,
95 cu->address_size, return_addr))
96 return -1;
97 return 0;
98
99 /* All others encode an index into the .debug_addr section where
100 the address can be found. */
101 case DW_FORM_GNU_addr_index:
102 case DW_FORM_addrx:
103 if (datap >= endp)
104 {
105 invalid:
106 __libdw_seterrno (DWARF_E_INVALID_DWARF);
107 return -1;
108 }
109 get_uleb128 (idx, datap, endp);
110 break;
111
112 case DW_FORM_addrx1:
113 if (datap >= endp - 1)
114 goto invalid;
115 idx = *datap;
116 break;
117
118 case DW_FORM_addrx2:
119 if (datap >= endp - 2)
120 goto invalid;
121 idx = read_2ubyte_unaligned (dbg, datap);
122 break;
123
124 case DW_FORM_addrx3:
125 if (datap >= endp - 3)
126 goto invalid;
127 idx = read_3ubyte_unaligned (dbg, datap);
128 break;
129
130 case DW_FORM_addrx4:
131 if (datap >= endp - 4)
132 goto invalid;
133 idx = read_4ubyte_unaligned (dbg, datap);
134 break;
135
136 default:
137 __libdw_seterrno (DWARF_E_NO_ADDR);
138 return -1;
139 }
140
141 /* So we got an index. Lets see if it is valid and we can get the actual
142 address. */
143 if (__libdw_addrx (cu, idx, return_addr) != 0)
144 return -1;
145
146 return 0;
147 }
148 INTDEF(dwarf_formaddr)
149