dwarf_getlocation.c revision c16966a0043dc173fcaab5d3f8b754b4e9c9ceb7
1/* Return location expression list.
2   Copyright (C) 2000-2010 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#include <assert.h>
59
60#include <libdwP.h>
61
62
63static bool
64attr_ok (Dwarf_Attribute *attr)
65{
66  if (attr == NULL)
67    return false;
68
69  /* Must be one of the attributes listed below.  */
70  switch (attr->code)
71    {
72    case DW_AT_location:
73    case DW_AT_data_member_location:
74    case DW_AT_vtable_elem_location:
75    case DW_AT_string_length:
76    case DW_AT_use_location:
77    case DW_AT_frame_base:
78    case DW_AT_return_addr:
79    case DW_AT_static_link:
80      break;
81
82    default:
83      __libdw_seterrno (DWARF_E_NO_LOCLIST);
84      return false;
85    }
86
87  return true;
88}
89
90
91struct loclist
92{
93  uint8_t atom;
94  Dwarf_Word number;
95  Dwarf_Word number2;
96  Dwarf_Word offset;
97  struct loclist *next;
98};
99
100
101static int
102loc_compare (const void *p1, const void *p2)
103{
104  const struct loc_s *l1 = (const struct loc_s *) p1;
105  const struct loc_s *l2 = (const struct loc_s *) p2;
106
107  if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
108    return -1;
109  if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
110    return 1;
111
112  return 0;
113}
114
115/* For each DW_OP_implicit_value, we store a special entry in the cache.
116   This points us directly to the block data for later fetching.  */
117static void
118store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op,
119		      unsigned char *data)
120{
121  struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
122					   sizeof (struct loc_block_s), 1);
123  block->addr = op;
124  block->data = data + op->number2;
125  block->length = op->number;
126  (void) tsearch (block, cache, loc_compare);
127}
128
129int
130dwarf_getlocation_implicit_value (attr, op, return_block)
131     Dwarf_Attribute *attr;
132     const Dwarf_Op *op;
133     Dwarf_Block *return_block;
134{
135  if (attr == NULL)
136    return -1;
137
138  struct loc_block_s fake = { .addr = (void *) op };
139  struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
140  if (unlikely (found == NULL))
141    {
142      __libdw_seterrno (DWARF_E_NO_BLOCK);
143      return -1;
144    }
145
146  return_block->length = (*found)->length;
147  return_block->data = (*found)->data;
148  return 0;
149}
150
151/* DW_AT_data_member_location can be a constant as well as a loclistptr.
152   Only data[48] indicate a loclistptr.  */
153static int
154check_constant_offset (Dwarf_Attribute *attr,
155		       Dwarf_Op **llbuf, size_t *listlen)
156{
157  if (attr->code != DW_AT_data_member_location)
158    return 1;
159
160  switch (attr->form)
161    {
162      /* Punt for any non-constant form.  */
163    default:
164      return 1;
165
166    case DW_FORM_data1:
167    case DW_FORM_data2:
168    case DW_FORM_data4:
169    case DW_FORM_data8:
170    case DW_FORM_sdata:
171    case DW_FORM_udata:
172      break;
173    }
174
175  /* Check whether we already cached this location.  */
176  struct loc_s fake = { .addr = attr->valp };
177  struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
178
179  if (found == NULL)
180    {
181      Dwarf_Word offset;
182      if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
183	return -1;
184
185      Dwarf_Op *result = libdw_alloc (attr->cu->dbg,
186				      Dwarf_Op, sizeof (Dwarf_Op), 1);
187
188      result->atom = DW_OP_plus_uconst;
189      result->number = offset;
190      result->number2 = 0;
191      result->offset = 0;
192
193      /* Insert a record in the search tree so we can find it again later.  */
194      struct loc_s *newp = libdw_alloc (attr->cu->dbg,
195					struct loc_s, sizeof (struct loc_s),
196					1);
197      newp->addr = attr->valp;
198      newp->loc = result;
199      newp->nloc = 1;
200
201      found = tsearch (newp, &attr->cu->locs, loc_compare);
202    }
203
204  assert ((*found)->nloc == 1);
205
206  if (llbuf != NULL)
207    {
208      *llbuf = (*found)->loc;
209      *listlen = 1;
210    }
211
212  return 0;
213}
214
215int
216internal_function
217__libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
218			   unsigned int address_size, unsigned int ref_size,
219			   void **cache, const Dwarf_Block *block,
220			   bool cfap, bool valuep,
221			   Dwarf_Op **llbuf, size_t *listlen, int sec_index)
222{
223  /* Check whether we already looked at this list.  */
224  struct loc_s fake = { .addr = block->data };
225  struct loc_s **found = tfind (&fake, cache, loc_compare);
226  if (found != NULL)
227    {
228      /* We already saw it.  */
229      *llbuf = (*found)->loc;
230      *listlen = (*found)->nloc;
231
232      if (valuep)
233	{
234	  assert (*listlen > 1);
235	  assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value);
236	}
237
238      return 0;
239    }
240
241  const unsigned char *data = block->data;
242  const unsigned char *const end_data = data + block->length;
243
244  const struct { bool other_byte_order; } bo = { other_byte_order };
245
246  struct loclist *loclist = NULL;
247  unsigned int n = 0;
248  /* Decode the opcodes.  It is possible in some situations to have a
249     block of size zero.  */
250  while (data < end_data)
251    {
252      struct loclist *newloc;
253      newloc = (struct loclist *) alloca (sizeof (struct loclist));
254      newloc->number = 0;
255      newloc->number2 = 0;
256      newloc->offset = data - block->data;
257      newloc->next = loclist;
258      loclist = newloc;
259      ++n;
260
261      switch ((newloc->atom = *data++))
262	{
263	case DW_OP_addr:
264	  /* Address, depends on address size of CU.  */
265	  if (__libdw_read_address_inc (dbg, sec_index, &data,
266					address_size, &newloc->number))
267	    return -1;
268	  break;
269
270	case DW_OP_call_ref:
271	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
272	  if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size,
273				       &newloc->number, IDX_debug_info, 0))
274	    return -1;
275	  break;
276
277	case DW_OP_deref:
278	case DW_OP_dup:
279	case DW_OP_drop:
280	case DW_OP_over:
281	case DW_OP_swap:
282	case DW_OP_rot:
283	case DW_OP_xderef:
284	case DW_OP_abs:
285	case DW_OP_and:
286	case DW_OP_div:
287	case DW_OP_minus:
288	case DW_OP_mod:
289	case DW_OP_mul:
290	case DW_OP_neg:
291	case DW_OP_not:
292	case DW_OP_or:
293	case DW_OP_plus:
294	case DW_OP_shl:
295	case DW_OP_shr:
296	case DW_OP_shra:
297	case DW_OP_xor:
298	case DW_OP_eq:
299	case DW_OP_ge:
300	case DW_OP_gt:
301	case DW_OP_le:
302	case DW_OP_lt:
303	case DW_OP_ne:
304	case DW_OP_lit0 ... DW_OP_lit31:
305	case DW_OP_reg0 ... DW_OP_reg31:
306	case DW_OP_nop:
307	case DW_OP_push_object_address:
308	case DW_OP_call_frame_cfa:
309	case DW_OP_form_tls_address:
310	case DW_OP_GNU_push_tls_address:
311	case DW_OP_stack_value:
312	  /* No operand.  */
313	  break;
314
315	case DW_OP_const1u:
316	case DW_OP_pick:
317	case DW_OP_deref_size:
318	case DW_OP_xderef_size:
319	  if (unlikely (data >= end_data))
320	    {
321	    invalid:
322	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
323	      return -1;
324	    }
325
326	  newloc->number = *data++;
327	  break;
328
329	case DW_OP_const1s:
330	  if (unlikely (data >= end_data))
331	    goto invalid;
332
333	  newloc->number = *((int8_t *) data);
334	  ++data;
335	  break;
336
337	case DW_OP_const2u:
338	  if (unlikely (data + 2 > end_data))
339	    goto invalid;
340
341	  newloc->number = read_2ubyte_unaligned_inc (&bo, data);
342	  break;
343
344	case DW_OP_const2s:
345	case DW_OP_skip:
346	case DW_OP_bra:
347	case DW_OP_call2:
348	  if (unlikely (data + 2 > end_data))
349	    goto invalid;
350
351	  newloc->number = read_2sbyte_unaligned_inc (&bo, data);
352	  break;
353
354	case DW_OP_const4u:
355	  if (unlikely (data + 4 > end_data))
356	    goto invalid;
357
358	  newloc->number = read_4ubyte_unaligned_inc (&bo, data);
359	  break;
360
361	case DW_OP_const4s:
362	case DW_OP_call4:
363	  if (unlikely (data + 4 > end_data))
364	    goto invalid;
365
366	  newloc->number = read_4sbyte_unaligned_inc (&bo, data);
367	  break;
368
369	case DW_OP_const8u:
370	  if (unlikely (data + 8 > end_data))
371	    goto invalid;
372
373	  newloc->number = read_8ubyte_unaligned_inc (&bo, data);
374	  break;
375
376	case DW_OP_const8s:
377	  if (unlikely (data + 8 > end_data))
378	    goto invalid;
379
380	  newloc->number = read_8sbyte_unaligned_inc (&bo, data);
381	  break;
382
383	case DW_OP_constu:
384	case DW_OP_plus_uconst:
385	case DW_OP_regx:
386	case DW_OP_piece:
387	  /* XXX Check size.  */
388	  get_uleb128 (newloc->number, data);
389	  break;
390
391	case DW_OP_consts:
392	case DW_OP_breg0 ... DW_OP_breg31:
393	case DW_OP_fbreg:
394	  /* XXX Check size.  */
395	  get_sleb128 (newloc->number, data);
396	  break;
397
398	case DW_OP_bregx:
399	  /* XXX Check size.  */
400	  get_uleb128 (newloc->number, data);
401	  get_sleb128 (newloc->number2, data);
402	  break;
403
404	case DW_OP_bit_piece:
405	  /* XXX Check size.  */
406	  get_uleb128 (newloc->number, data);
407	  get_uleb128 (newloc->number2, data);
408	  break;
409
410	case DW_OP_implicit_value:
411	  /* This cannot be used in a CFI expression.  */
412	  if (unlikely (dbg == NULL))
413	    goto invalid;
414
415	  /* XXX Check size.  */
416	  get_uleb128 (newloc->number, data); /* Block length.  */
417	  if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
418	    goto invalid;
419	  newloc->number2 = data - block->data; /* Relative block offset.  */
420	  data += newloc->number;		/* Skip the block.  */
421	  break;
422
423	default:
424	  goto invalid;
425	}
426    }
427
428  if (unlikely (n == 0))
429    {
430      /* This is not allowed.
431
432	 XXX Is it?  */
433      goto invalid;
434    }
435
436  if (valuep)
437    {
438      struct loclist *newloc;
439      newloc = (struct loclist *) alloca (sizeof (struct loclist));
440      newloc->atom = DW_OP_stack_value;
441      newloc->number = 0;
442      newloc->number2 = 0;
443      newloc->offset = data - block->data;
444      newloc->next = loclist;
445      loclist = newloc;
446      ++n;
447    }
448
449  if (cfap)
450    ++n;
451
452  /* Allocate the array.  */
453  Dwarf_Op *result;
454  if (dbg != NULL)
455    result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
456  else
457    {
458      result = malloc (sizeof *result * n);
459      if (result == NULL)
460	{
461	nomem:
462	  __libdw_seterrno (DWARF_E_NOMEM);
463	  return -1;
464	}
465    }
466
467  /* Store the result.  */
468  *llbuf = result;
469  *listlen = n;
470
471  if (cfap)
472    {
473      /* Synthesize the operation to push the CFA before the expression.  */
474      --n;
475      result[0].atom = DW_OP_call_frame_cfa;
476      result[0].number = 0;
477      result[0].number2 = 0;
478      result[0].offset = -1;
479    }
480
481  do
482    {
483      /* We populate the array from the back since the list is backwards.  */
484      --n;
485      result[n].atom = loclist->atom;
486      result[n].number = loclist->number;
487      result[n].number2 = loclist->number2;
488      result[n].offset = loclist->offset;
489
490      if (result[n].atom == DW_OP_implicit_value)
491	store_implicit_value (dbg, cache, &result[n], block->data);
492
493      loclist = loclist->next;
494    }
495  while (n > 0);
496
497  /* Insert a record in the search tree so that we can find it again later.  */
498  struct loc_s *newp;
499  if (dbg != NULL)
500    newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
501  else
502    {
503      newp = malloc (sizeof *newp);
504      if (newp == NULL)
505	{
506	  free (result);
507	  goto nomem;
508	}
509    }
510
511  newp->addr = block->data;
512  newp->loc = result;
513  newp->nloc = *listlen;
514  (void) tsearch (newp, cache, loc_compare);
515
516  /* We did it.  */
517  return 0;
518}
519
520static int
521getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
522	     Dwarf_Op **llbuf, size_t *listlen, int sec_index)
523{
524  return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
525				    cu->address_size, (cu->version == 2
526						       ? cu->address_size
527						       : cu->offset_size),
528				    &cu->locs, block,
529				    false, false,
530				    llbuf, listlen, sec_index);
531}
532
533int
534dwarf_getlocation (attr, llbuf, listlen)
535     Dwarf_Attribute *attr;
536     Dwarf_Op **llbuf;
537     size_t *listlen;
538{
539  if (! attr_ok (attr))
540    return -1;
541
542  int result = check_constant_offset (attr, llbuf, listlen);
543  if (result != 1)
544    return result;
545
546  /* If it has a block form, it's a single location expression.  */
547  Dwarf_Block block;
548  if (INTUSE(dwarf_formblock) (attr, &block) != 0)
549    return -1;
550
551  return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
552}
553
554int
555dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
556     Dwarf_Attribute *attr;
557     Dwarf_Addr address;
558     Dwarf_Op **llbufs;
559     size_t *listlens;
560     size_t maxlocs;
561{
562  if (! attr_ok (attr))
563    return -1;
564
565  if (llbufs == NULL)
566    maxlocs = SIZE_MAX;
567
568  /* If it has a block form, it's a single location expression.  */
569  Dwarf_Block block;
570  if (INTUSE(dwarf_formblock) (attr, &block) == 0)
571    {
572      if (maxlocs == 0)
573	return 0;
574      if (llbufs != NULL &&
575	  getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
576		       cu_sec_idx (attr->cu)) != 0)
577	return -1;
578      return listlens[0] == 0 ? 0 : 1;
579    }
580
581  int error = INTUSE(dwarf_errno) ();
582  if (unlikely (error != DWARF_E_NO_BLOCK))
583    {
584      __libdw_seterrno (error);
585      return -1;
586    }
587
588  int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
589  if (result != 1)
590    return result ?: 1;
591
592  unsigned char *endp;
593  unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc,
594					  DWARF_E_NO_LOCLIST, &endp, NULL);
595  if (readp == NULL)
596    return -1;
597
598  Dwarf_Addr base = (Dwarf_Addr) -1;
599  size_t got = 0;
600  while (got < maxlocs)
601    {
602      if (endp - readp < attr->cu->address_size * 2)
603	{
604	invalid:
605	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
606	  return -1;
607	}
608
609      Dwarf_Addr begin;
610      Dwarf_Addr end;
611
612      int status
613	= __libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
614					   &readp, attr->cu->address_size,
615					   &begin, &end, &base);
616      if (status == 2) /* End of list entry.  */
617	break;
618      else if (status == 1) /* Base address selected.  */
619	continue;
620      else if (status < 0)
621	return status;
622
623      if (endp - readp < 2)
624	goto invalid;
625
626      /* We have a location expression.  */
627      block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
628      block.data = readp;
629      if (endp - readp < (ptrdiff_t) block.length)
630	goto invalid;
631      readp += block.length;
632
633      if (base == (Dwarf_Addr) -1)
634	{
635	  /* Fetch the CU's base address.  */
636	  Dwarf_Die cudie = CUDIE (attr->cu);
637
638	  /* Find the base address of the compilation unit.  It will
639	     normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
640	     the base address could be overridden by DW_AT_entry_pc.  It's
641	     been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
642	     for compilation units with discontinuous ranges.  */
643	  Dwarf_Attribute attr_mem;
644	  if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0)
645	      && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
646							     DW_AT_entry_pc,
647							     &attr_mem),
648					 &base) != 0)
649	    {
650	      if (INTUSE(dwarf_errno) () != 0)
651		return -1;
652
653	      /* The compiler provided no base address when it should
654		 have.  Buggy GCC does this when it used absolute
655		 addresses in the location list and no DW_AT_ranges.  */
656	      base = 0;
657	    }
658	}
659
660      if (address >= base + begin && address < base + end)
661	{
662	  /* This one matches the address.  */
663	  if (llbufs != NULL
664	      && unlikely (getlocation (attr->cu, &block,
665					&llbufs[got], &listlens[got],
666					IDX_debug_loc) != 0))
667	    return -1;
668	  ++got;
669	}
670    }
671
672  return got;
673}
674