]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/elftoolchain/libdwarf/dwarf_loclist.c
bhnd(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / contrib / elftoolchain / libdwarf / dwarf_loclist.c
1 /*-
2  * Copyright (c) 2009,2014 Kai Wang
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include "_libdwarf.h"
28
29 ELFTC_VCSID("$Id: dwarf_loclist.c 3066 2014-06-06 19:36:06Z kaiwang27 $");
30
31 static int
32 copy_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *dst, Dwarf_Locdesc *src,
33     Dwarf_Error *error)
34 {
35
36         assert(src != NULL && dst != NULL);
37
38         dst->ld_lopc = src->ld_lopc;
39         dst->ld_hipc = src->ld_hipc;
40         dst->ld_cents = src->ld_cents;
41
42         if (dst->ld_cents > 0) {
43                 dst->ld_s = calloc(dst->ld_cents, sizeof(Dwarf_Loc));
44                 if (dst->ld_s == NULL) {
45                         DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
46                         return (DW_DLE_MEMORY);
47                 }
48                 memcpy(dst->ld_s, src->ld_s, src->ld_cents *
49                     sizeof(Dwarf_Loc));
50         } else
51                 dst->ld_s = NULL;
52
53         return (DW_DLE_NONE);
54 }
55
56 int
57 dwarf_loclist_n(Dwarf_Attribute at, Dwarf_Locdesc ***llbuf,
58     Dwarf_Signed *listlen, Dwarf_Error *error)
59 {
60         Dwarf_Debug dbg;
61         int ret;
62
63         dbg = at != NULL ? at->at_die->die_dbg : NULL;
64
65         if (at == NULL || llbuf == NULL || listlen == NULL) {
66                 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
67                 return (DW_DLV_ERROR);
68         }
69
70         switch (at->at_attrib) {
71         case DW_AT_location:
72         case DW_AT_string_length:
73         case DW_AT_return_addr:
74         case DW_AT_data_member_location:
75         case DW_AT_frame_base:
76         case DW_AT_segment:
77         case DW_AT_static_link:
78         case DW_AT_use_location:
79         case DW_AT_vtable_elem_location:
80                 switch (at->at_form) {
81                 case DW_FORM_data4:
82                 case DW_FORM_data8:
83                         /*
84                          * DW_FORM_data[48] can not be used as section offset
85                          * since DWARF4. For DWARF[23], the application needs
86                          * to determine if DW_FORM_data[48] is representing
87                          * a constant or a section offset.
88                          */
89                         if (at->at_die->die_cu->cu_version >= 4) {
90                                 DWARF_SET_ERROR(dbg, error, DW_DLE_NO_ENTRY);
91                                 return (DW_DLV_NO_ENTRY);
92                         }
93                         /* FALLTHROUGH */
94                 case DW_FORM_sec_offset:
95                         ret = _dwarf_loclist_find(dbg, at->at_die->die_cu,
96                             at->u[0].u64, llbuf, listlen, NULL, error);
97                         if (ret == DW_DLE_NO_ENTRY) {
98                                 DWARF_SET_ERROR(dbg, error, ret);
99                                 return (DW_DLV_NO_ENTRY);
100                         }
101                         if (ret != DW_DLE_NONE)
102                                 return (DW_DLV_ERROR);
103                         return (DW_DLV_OK);
104                 case DW_FORM_block:
105                 case DW_FORM_block1:
106                 case DW_FORM_block2:
107                 case DW_FORM_block4:
108                 case DW_FORM_exprloc:
109                         if (at->at_ld == NULL) {
110                                 ret = _dwarf_loc_add(at->at_die, at, error);
111                                 if (ret != DW_DLE_NONE)
112                                         return (DW_DLV_ERROR);
113                         }
114                         *llbuf = calloc(1, sizeof(Dwarf_Locdesc *));
115                         if (*llbuf == NULL) {
116                                 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
117                                 return (DW_DLV_ERROR);
118                         }
119                         (*llbuf)[0] = calloc(1, sizeof(Dwarf_Locdesc));
120                         if ((*llbuf)[0] == NULL) {
121                                 free(*llbuf);
122                                 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
123                                 return (DW_DLV_ERROR);
124                         }
125                         if (copy_locdesc(dbg, (*llbuf)[0], at->at_ld, error) !=
126                             DW_DLE_NONE) {
127                                 free((*llbuf)[0]);
128                                 free(*llbuf);
129                                 return (DW_DLV_ERROR);
130                         }
131                         *listlen = 1;
132                         return (DW_DLV_OK);
133                 default:
134                         /* Malformed Attr? */
135                         DWARF_SET_ERROR(dbg, error, DW_DLE_ATTR_FORM_BAD);
136                         return (DW_DLV_NO_ENTRY);
137                 }
138         default:
139                 /* Wrong attr supplied. */
140                 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
141                 return (DW_DLV_ERROR);
142         }
143 }
144
145 int
146 dwarf_loclist(Dwarf_Attribute at, Dwarf_Locdesc **llbuf,
147     Dwarf_Signed *listlen, Dwarf_Error *error)
148 {
149         Dwarf_Locdesc **_llbuf;
150         int i, ret;
151
152         ret = dwarf_loclist_n(at, &_llbuf, listlen, error);
153         if (ret != DW_DLV_OK)
154                 return (ret);
155
156         /* Only return the first location description of the list. */
157         *llbuf = _llbuf[0];
158
159         /* Free the rest of the list. */
160         for (i = 1; i < *listlen; i++) {
161                 if (_llbuf[i]->ld_s)
162                         free(_llbuf[i]->ld_s);
163                 free(_llbuf[i]);
164         }
165         free(_llbuf);
166
167         *listlen = 1;
168
169         return (DW_DLV_OK);
170 }
171
172 int
173 dwarf_get_loclist_entry(Dwarf_Debug dbg, Dwarf_Unsigned offset,
174     Dwarf_Addr *hipc, Dwarf_Addr *lopc, Dwarf_Ptr *data,
175     Dwarf_Unsigned *entry_len, Dwarf_Unsigned *next_entry,
176     Dwarf_Error *error)
177 {
178         Dwarf_Locdesc *ld, **llbuf;
179         Dwarf_Section *ds;
180         Dwarf_Signed listlen;
181         int i, ret;
182
183         /*
184          * Note that this API sometimes will not work correctly because
185          * it assumes that all units have the same pointer size and offset
186          * size.
187          */
188
189         if (dbg == NULL || hipc == NULL || lopc == NULL || data == NULL ||
190             entry_len == NULL || next_entry == NULL) {
191                 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
192                 return (DW_DLV_ERROR);
193         }
194
195         ret = _dwarf_loclist_find(dbg, STAILQ_FIRST(&dbg->dbg_cu), offset,
196             &llbuf, &listlen, entry_len, error);
197         if (ret == DW_DLE_NO_ENTRY) {
198                 DWARF_SET_ERROR(dbg, error, DW_DLV_NO_ENTRY);
199                 return (DW_DLV_NO_ENTRY);
200         } else if (ret != DW_DLE_NONE)
201                 return (DW_DLV_ERROR);
202
203         *hipc = *lopc = 0;
204         for (i = 0; i < listlen; i++) {
205                 ld = llbuf[i];
206                 if (i == 0) {
207                         *hipc = ld->ld_hipc;
208                         *lopc = ld->ld_lopc;
209                 } else {
210                         if (ld->ld_lopc < *lopc)
211                                 *lopc = ld->ld_lopc;
212                         if (ld->ld_hipc > *hipc)
213                                 *hipc = ld->ld_hipc;
214                 }
215         }
216
217         ds = _dwarf_find_section(dbg, ".debug_loc");
218         assert(ds != NULL);
219         *data = (uint8_t *) ds->ds_data + offset;
220         *next_entry = offset + *entry_len;
221
222         return (DW_DLV_OK);
223 }
224
225 int
226 dwarf_loclist_from_expr(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
227     Dwarf_Unsigned bytes_len, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
228     Dwarf_Error *error)
229 {
230
231         return (dwarf_loclist_from_expr_a(dbg, bytes_in, bytes_len,
232             dbg->dbg_pointer_size, llbuf, listlen, error));
233 }
234
235 int
236 dwarf_loclist_from_expr_a(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
237     Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Locdesc **llbuf,
238     Dwarf_Signed *listlen, Dwarf_Error *error)
239 {
240         Dwarf_Half offset_size;
241         Dwarf_Small version;
242
243         /*
244          * Obtain offset size and DWARF version from the current
245          * Compilation Unit or Type Unit. These values are needed
246          * for correctly parsing DW_OP_GNU_implicit_pointer operator.
247          *
248          * Note that dwarf_loclist_from_expr_b() should be used instead
249          * if the application knows correct values for offset size
250          * and DWARF version.
251          */
252         if (dbg->dbg_cu_current) {
253                 offset_size = dbg->dbg_cu_current->cu_length_size == 4 ? 4 : 8;
254                 version = dbg->dbg_cu_current->cu_version;
255         } else if (dbg->dbg_tu_current) {
256                 offset_size = dbg->dbg_tu_current->cu_length_size == 4 ? 4 : 8;
257                 version = dbg->dbg_tu_current->cu_version;
258         } else {
259                 /* Default values if no CU/TU context. */
260                 offset_size = 4;
261                 version = 2;    /* DWARF2 */
262         }
263
264         return (dwarf_loclist_from_expr_b(dbg, bytes_in, bytes_len, addr_size,
265             offset_size, version, llbuf, listlen, error));
266 }
267
268 int
269 dwarf_loclist_from_expr_b(Dwarf_Debug dbg, Dwarf_Ptr bytes_in,
270     Dwarf_Unsigned bytes_len, Dwarf_Half addr_size, Dwarf_Half offset_size,
271     Dwarf_Small version, Dwarf_Locdesc **llbuf, Dwarf_Signed *listlen,
272     Dwarf_Error *error)
273 {
274         Dwarf_Locdesc *ld;
275         int ret;
276
277         if (dbg == NULL || bytes_in == NULL || bytes_len == 0 ||
278             llbuf == NULL || listlen == NULL) {
279                 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
280                 return (DW_DLV_ERROR);
281         }
282
283         if (addr_size != 4 && addr_size != 8) {
284                 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
285                 return (DW_DLV_ERROR);
286         }
287
288         if (offset_size != 4 && offset_size != 8) {
289                 DWARF_SET_ERROR(dbg, error, DW_DLE_ARGUMENT);
290                 return (DW_DLV_ERROR);
291         }
292
293         ret = _dwarf_loc_fill_locexpr(dbg, &ld, bytes_in, bytes_len, addr_size,
294             offset_size, version, error);
295         if (ret != DW_DLE_NONE)
296                 return (DW_DLV_ERROR);
297
298         *llbuf = ld;
299         *listlen = 1;
300
301         return (DW_DLV_OK);
302 }