• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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