1 /* Return location expression list.
2 Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc.
3 This file is part of Red Hat elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
6 Red Hat elfutils is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 2 of the License.
9
10 Red Hat elfutils is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with Red Hat elfutils; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18
19 In addition, as a special exception, Red Hat, Inc. gives You the
20 additional right to link the code of Red Hat elfutils with code licensed
21 under any Open Source Initiative certified open source license
22 (http://www.opensource.org/licenses/index.php) which requires the
23 distribution of source code with any binary distribution and to
24 distribute linked combinations of the two. Non-GPL Code permitted under
25 this exception must only link to the code of Red Hat elfutils through
26 those well defined interfaces identified in the file named EXCEPTION
27 found in the source code files (the "Approved Interfaces"). The files
28 of Non-GPL Code may instantiate templates or use macros or inline
29 functions from the Approved Interfaces without causing the resulting
30 work to be covered by the GNU General Public License. Only Red Hat,
31 Inc. may make changes or additions to the list of Approved Interfaces.
32 Red Hat's grant of this exception is conditioned upon your not adding
33 any new exceptions. If you wish to add a new Approved Interface or
34 exception, please contact Red Hat. You must obey the GNU General Public
35 License in all respects for all of the Red Hat elfutils code and other
36 code used in conjunction with Red Hat elfutils except the Non-GPL Code
37 covered by this exception. If you modify this file, you may extend this
38 exception to your version of the file, but you are not obligated to do
39 so. If you do not wish to provide this exception without modification,
40 you must delete this exception statement from your version and license
41 this file solely under the GPL without exception.
42
43 Red Hat elfutils is an included package of the Open Invention Network.
44 An included package of the Open Invention Network is a package for which
45 Open Invention Network licensees cross-license their patents. No patent
46 license is granted, either expressly or impliedly, by designation as an
47 included package. Should you wish to participate in the Open Invention
48 Network licensing program, please visit www.openinventionnetwork.com
49 <http://www.openinventionnetwork.com>. */
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54
55 #include <dwarf.h>
56 #include <search.h>
57 #include <stdlib.h>
58
59 #include <libdwP.h>
60
61
62 static bool
attr_ok(Dwarf_Attribute * attr)63 attr_ok (Dwarf_Attribute *attr)
64 {
65 if (attr == NULL)
66 return false;
67
68 /* Must be one of the attributes listed below. */
69 switch (attr->code)
70 {
71 case DW_AT_location:
72 case DW_AT_data_member_location:
73 case DW_AT_vtable_elem_location:
74 case DW_AT_string_length:
75 case DW_AT_use_location:
76 case DW_AT_frame_base:
77 case DW_AT_return_addr:
78 case DW_AT_static_link:
79 break;
80
81 default:
82 __libdw_seterrno (DWARF_E_NO_LOCLIST);
83 return false;
84 }
85
86 return true;
87 }
88
89
90 struct loclist
91 {
92 uint8_t atom;
93 Dwarf_Word number;
94 Dwarf_Word number2;
95 Dwarf_Word offset;
96 struct loclist *next;
97 };
98
99
100 static int
loc_compare(const void * p1,const void * p2)101 loc_compare (const void *p1, const void *p2)
102 {
103 const struct loc_s *l1 = (const struct loc_s *) p1;
104 const struct loc_s *l2 = (const struct loc_s *) p2;
105
106 if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
107 return -1;
108 if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
109 return 1;
110
111 return 0;
112 }
113
114 static int
getlocation(struct Dwarf_CU * cu,const Dwarf_Block * block,Dwarf_Op ** llbuf,size_t * listlen)115 getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
116 Dwarf_Op **llbuf, size_t *listlen)
117 {
118 Dwarf *dbg = cu->dbg;
119
120 /* Check whether we already looked at this list. */
121 struct loc_s fake = { .addr = block->data };
122 struct loc_s **found = tfind (&fake, &cu->locs, loc_compare);
123 if (found != NULL)
124 {
125 /* We already saw it. */
126 *llbuf = (*found)->loc;
127 *listlen = (*found)->nloc;
128
129 return 0;
130 }
131
132 const unsigned char *data = block->data;
133 const unsigned char *const end_data = data + block->length;
134
135 struct loclist *loclist = NULL;
136 unsigned int n = 0;
137 /* Decode the opcodes. It is possible in some situations to have a
138 block of size zero. */
139 while (data < end_data)
140 {
141 struct loclist *newloc;
142 newloc = (struct loclist *) alloca (sizeof (struct loclist));
143 newloc->number = 0;
144 newloc->number2 = 0;
145 newloc->offset = data - block->data;
146 newloc->next = loclist;
147 loclist = newloc;
148 ++n;
149
150 switch ((newloc->atom = *data++))
151 {
152 case DW_OP_addr:
153 /* Address, depends on address size of CU. */
154 if (cu->address_size == 4)
155 {
156 if (unlikely (data + 4 > end_data))
157 {
158 invalid:
159 __libdw_seterrno (DWARF_E_INVALID_DWARF);
160 return -1;
161 }
162
163 newloc->number = read_4ubyte_unaligned_inc (dbg, data);
164 }
165 else
166 {
167 if (unlikely (data + 8 > end_data))
168 goto invalid;
169
170 newloc->number = read_8ubyte_unaligned_inc (dbg, data);
171 }
172 break;
173
174 case DW_OP_deref:
175 case DW_OP_dup:
176 case DW_OP_drop:
177 case DW_OP_over:
178 case DW_OP_swap:
179 case DW_OP_rot:
180 case DW_OP_xderef:
181 case DW_OP_abs:
182 case DW_OP_and:
183 case DW_OP_div:
184 case DW_OP_minus:
185 case DW_OP_mod:
186 case DW_OP_mul:
187 case DW_OP_neg:
188 case DW_OP_not:
189 case DW_OP_or:
190 case DW_OP_plus:
191 case DW_OP_shl:
192 case DW_OP_shr:
193 case DW_OP_shra:
194 case DW_OP_xor:
195 case DW_OP_eq:
196 case DW_OP_ge:
197 case DW_OP_gt:
198 case DW_OP_le:
199 case DW_OP_lt:
200 case DW_OP_ne:
201 case DW_OP_lit0 ... DW_OP_lit31:
202 case DW_OP_reg0 ... DW_OP_reg31:
203 case DW_OP_nop:
204 case DW_OP_push_object_address:
205 case DW_OP_call_ref:
206 /* No operand. */
207 break;
208
209 case DW_OP_const1u:
210 case DW_OP_pick:
211 case DW_OP_deref_size:
212 case DW_OP_xderef_size:
213 if (unlikely (data >= end_data))
214 goto invalid;
215
216 newloc->number = *data++;
217 break;
218
219 case DW_OP_const1s:
220 if (unlikely (data >= end_data))
221 goto invalid;
222
223 newloc->number = *((int8_t *) data);
224 ++data;
225 break;
226
227 case DW_OP_const2u:
228 if (unlikely (data + 2 > end_data))
229 goto invalid;
230
231 newloc->number = read_2ubyte_unaligned_inc (dbg, data);
232 break;
233
234 case DW_OP_const2s:
235 case DW_OP_skip:
236 case DW_OP_bra:
237 case DW_OP_call2:
238 if (unlikely (data + 2 > end_data))
239 goto invalid;
240
241 newloc->number = read_2sbyte_unaligned_inc (dbg, data);
242 break;
243
244 case DW_OP_const4u:
245 if (unlikely (data + 4 > end_data))
246 goto invalid;
247
248 newloc->number = read_4ubyte_unaligned_inc (dbg, data);
249 break;
250
251 case DW_OP_const4s:
252 case DW_OP_call4:
253 if (unlikely (data + 4 > end_data))
254 goto invalid;
255
256 newloc->number = read_4sbyte_unaligned_inc (dbg, data);
257 break;
258
259 case DW_OP_const8u:
260 if (unlikely (data + 8 > end_data))
261 goto invalid;
262
263 newloc->number = read_8ubyte_unaligned_inc (dbg, data);
264 break;
265
266 case DW_OP_const8s:
267 if (unlikely (data + 8 > end_data))
268 goto invalid;
269
270 newloc->number = read_8sbyte_unaligned_inc (dbg, data);
271 break;
272
273 case DW_OP_constu:
274 case DW_OP_plus_uconst:
275 case DW_OP_regx:
276 case DW_OP_piece:
277 /* XXX Check size. */
278 get_uleb128 (newloc->number, data);
279 break;
280
281 case DW_OP_consts:
282 case DW_OP_breg0 ... DW_OP_breg31:
283 case DW_OP_fbreg:
284 /* XXX Check size. */
285 get_sleb128 (newloc->number, data);
286 break;
287
288 case DW_OP_bregx:
289 /* XXX Check size. */
290 get_uleb128 (newloc->number, data);
291 get_sleb128 (newloc->number2, data);
292 break;
293
294 default:
295 goto invalid;
296 }
297 }
298
299 if (unlikely (n == 0))
300 {
301 /* This is not allowed.
302
303 XXX Is it? */
304 goto invalid;
305 }
306
307 /* Allocate the array. */
308 Dwarf_Op *result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
309
310 /* Store the result. */
311 *llbuf = result;
312 *listlen = n;
313
314 do
315 {
316 /* We populate the array from the back since the list is
317 backwards. */
318 --n;
319 result[n].atom = loclist->atom;
320 result[n].number = loclist->number;
321 result[n].number2 = loclist->number2;
322 result[n].offset = loclist->offset;
323
324 loclist = loclist->next;
325 }
326 while (n > 0);
327
328 /* Insert a record in the search tree so that we can find it again
329 later. */
330 struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s),
331 1);
332 newp->addr = block->data;
333 newp->loc = result;
334 newp->nloc = *listlen;
335 (void) tsearch (newp, &cu->locs, loc_compare);
336
337 /* We did it. */
338 return 0;
339 }
340
341 int
dwarf_getlocation(attr,llbuf,listlen)342 dwarf_getlocation (attr, llbuf, listlen)
343 Dwarf_Attribute *attr;
344 Dwarf_Op **llbuf;
345 size_t *listlen;
346 {
347 if (! attr_ok (attr))
348 return -1;
349
350 /* If it has a block form, it's a single location expression. */
351 Dwarf_Block block;
352 if (INTUSE(dwarf_formblock) (attr, &block) != 0)
353 return -1;
354
355 return getlocation (attr->cu, &block, llbuf, listlen);
356 }
357
358 int
dwarf_getlocation_addr(attr,address,llbufs,listlens,maxlocs)359 dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
360 Dwarf_Attribute *attr;
361 Dwarf_Addr address;
362 Dwarf_Op **llbufs;
363 size_t *listlens;
364 size_t maxlocs;
365 {
366 if (! attr_ok (attr))
367 return -1;
368
369 if (llbufs == NULL)
370 maxlocs = SIZE_MAX;
371
372 /* If it has a block form, it's a single location expression. */
373 Dwarf_Block block;
374 if (INTUSE(dwarf_formblock) (attr, &block) == 0)
375 {
376 if (maxlocs == 0)
377 return 0;
378 if (llbufs != NULL &&
379 getlocation (attr->cu, &block, &llbufs[0], &listlens[0]) != 0)
380 return -1;
381 return listlens[0] == 0 ? 0 : 1;
382 }
383
384 int error = INTUSE(dwarf_errno) ();
385 if (unlikely (error != DWARF_E_NO_BLOCK))
386 {
387 __libdw_seterrno (error);
388 return -1;
389 }
390
391 /* Must have the form data4 or data8 which act as an offset. */
392 Dwarf_Word offset;
393 if (unlikely (INTUSE(dwarf_formudata) (attr, &offset) != 0))
394 return -1;
395
396 const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
397 if (unlikely (d == NULL))
398 {
399 __libdw_seterrno (DWARF_E_NO_LOCLIST);
400 return -1;
401 }
402
403 Dwarf_Addr base = (Dwarf_Addr) -1;
404 unsigned char *readp = d->d_buf + offset;
405 size_t got = 0;
406 while (got < maxlocs)
407 {
408 if ((unsigned char *) d->d_buf + d->d_size - readp
409 < attr->cu->address_size * 2)
410 {
411 invalid:
412 __libdw_seterrno (DWARF_E_INVALID_DWARF);
413 return -1;
414 }
415
416 Dwarf_Addr begin;
417 Dwarf_Addr end;
418 if (attr->cu->address_size == 8)
419 {
420 begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);
421 end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp);
422
423 if (begin == (Elf64_Addr) -1l) /* Base address entry. */
424 {
425 base = end;
426 if (unlikely (base == (Dwarf_Addr) -1))
427 goto invalid;
428 continue;
429 }
430 }
431 else
432 {
433 begin = read_4ubyte_unaligned_inc (attr->cu->dbg, readp);
434 end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp);
435
436 if (begin == (Elf32_Addr) -1) /* Base address entry. */
437 {
438 base = end;
439 continue;
440 }
441 }
442
443 if (begin == 0 && end == 0) /* End of list entry. */
444 break;
445
446 if ((unsigned char *) d->d_buf + d->d_size - readp < 2)
447 goto invalid;
448
449 /* We have a location expression. */
450 block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
451 block.data = readp;
452 if ((unsigned char *) d->d_buf + d->d_size - readp
453 < (ptrdiff_t) block.length)
454 goto invalid;
455 readp += block.length;
456
457 if (base == (Dwarf_Addr) -1)
458 {
459 /* Fetch the CU's base address. */
460 Dwarf_Die cudie = CUDIE (attr->cu);
461
462 /* Find the base address of the compilation unit. It will
463 normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
464 the base address could be overridden by DW_AT_entry_pc. It's
465 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
466 for compilation units with discontinuous ranges. */
467 Dwarf_Attribute attr_mem;
468 if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0)
469 && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
470 DW_AT_entry_pc,
471 &attr_mem),
472 &base) != 0)
473 {
474 if (INTUSE(dwarf_errno) () != 0)
475 return -1;
476
477 /* The compiler provided no base address when it should
478 have. Buggy GCC does this when it used absolute
479 addresses in the location list and no DW_AT_ranges. */
480 base = 0;
481 }
482 }
483
484 if (address >= base + begin && address < base + end)
485 {
486 /* This one matches the address. */
487 if (llbufs != NULL
488 && unlikely (getlocation (attr->cu, &block,
489 &llbufs[got], &listlens[got]) != 0))
490 return -1;
491 ++got;
492 }
493 }
494
495 return got;
496 }
497