1da0c48c4Sopenharmony_ci/* Return location expression list.
2da0c48c4Sopenharmony_ci   Copyright (C) 2000-2010, 2013-2015, 2017, 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include <dwarf.h>
34da0c48c4Sopenharmony_ci#include <search.h>
35da0c48c4Sopenharmony_ci#include <stdlib.h>
36da0c48c4Sopenharmony_ci#include <assert.h>
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_ci#include <libdwP.h>
39da0c48c4Sopenharmony_ci
40da0c48c4Sopenharmony_ci
41da0c48c4Sopenharmony_cistatic bool
42da0c48c4Sopenharmony_ciattr_ok (Dwarf_Attribute *attr)
43da0c48c4Sopenharmony_ci{
44da0c48c4Sopenharmony_ci  if (attr == NULL)
45da0c48c4Sopenharmony_ci    return false;
46da0c48c4Sopenharmony_ci
47da0c48c4Sopenharmony_ci  /* If it is an exprloc, it is obviously OK.  */
48da0c48c4Sopenharmony_ci  if (dwarf_whatform (attr) == DW_FORM_exprloc)
49da0c48c4Sopenharmony_ci    return true;
50da0c48c4Sopenharmony_ci
51da0c48c4Sopenharmony_ci  if (attr->cu->version >= 4)
52da0c48c4Sopenharmony_ci    {
53da0c48c4Sopenharmony_ci      /* Must be an exprloc (or constant), just not any block form.  */
54da0c48c4Sopenharmony_ci      switch (dwarf_whatform (attr))
55da0c48c4Sopenharmony_ci	{
56da0c48c4Sopenharmony_ci	case DW_FORM_block:
57da0c48c4Sopenharmony_ci	case DW_FORM_block1:
58da0c48c4Sopenharmony_ci	case DW_FORM_block2:
59da0c48c4Sopenharmony_ci	case DW_FORM_block4:
60da0c48c4Sopenharmony_ci	  __libdw_seterrno (DWARF_E_NO_LOC_VALUE);
61da0c48c4Sopenharmony_ci	  return false;
62da0c48c4Sopenharmony_ci	default:
63da0c48c4Sopenharmony_ci	  break;
64da0c48c4Sopenharmony_ci	}
65da0c48c4Sopenharmony_ci    }
66da0c48c4Sopenharmony_ci
67da0c48c4Sopenharmony_ci  /* Otherwise must be one of the attributes listed below.  Older
68da0c48c4Sopenharmony_ci     DWARF versions might have encoded the exprloc as block, and we
69da0c48c4Sopenharmony_ci     cannot easily distinguish attributes in the loclist class because
70da0c48c4Sopenharmony_ci     the same forms are used for different classes.  */
71da0c48c4Sopenharmony_ci  switch (attr->code)
72da0c48c4Sopenharmony_ci    {
73da0c48c4Sopenharmony_ci    case DW_AT_location:
74da0c48c4Sopenharmony_ci    case DW_AT_byte_size:
75da0c48c4Sopenharmony_ci    case DW_AT_bit_offset:
76da0c48c4Sopenharmony_ci    case DW_AT_bit_size:
77da0c48c4Sopenharmony_ci    case DW_AT_lower_bound:
78da0c48c4Sopenharmony_ci    case DW_AT_bit_stride:
79da0c48c4Sopenharmony_ci    case DW_AT_upper_bound:
80da0c48c4Sopenharmony_ci    case DW_AT_count:
81da0c48c4Sopenharmony_ci    case DW_AT_allocated:
82da0c48c4Sopenharmony_ci    case DW_AT_associated:
83da0c48c4Sopenharmony_ci    case DW_AT_data_location:
84da0c48c4Sopenharmony_ci    case DW_AT_byte_stride:
85da0c48c4Sopenharmony_ci    case DW_AT_rank:
86da0c48c4Sopenharmony_ci    case DW_AT_call_value:
87da0c48c4Sopenharmony_ci    case DW_AT_call_target:
88da0c48c4Sopenharmony_ci    case DW_AT_call_target_clobbered:
89da0c48c4Sopenharmony_ci    case DW_AT_call_data_location:
90da0c48c4Sopenharmony_ci    case DW_AT_call_data_value:
91da0c48c4Sopenharmony_ci    case DW_AT_data_member_location:
92da0c48c4Sopenharmony_ci    case DW_AT_vtable_elem_location:
93da0c48c4Sopenharmony_ci    case DW_AT_string_length:
94da0c48c4Sopenharmony_ci    case DW_AT_use_location:
95da0c48c4Sopenharmony_ci    case DW_AT_frame_base:
96da0c48c4Sopenharmony_ci    case DW_AT_return_addr:
97da0c48c4Sopenharmony_ci    case DW_AT_static_link:
98da0c48c4Sopenharmony_ci    case DW_AT_segment:
99da0c48c4Sopenharmony_ci    case DW_AT_GNU_call_site_value:
100da0c48c4Sopenharmony_ci    case DW_AT_GNU_call_site_data_value:
101da0c48c4Sopenharmony_ci    case DW_AT_GNU_call_site_target:
102da0c48c4Sopenharmony_ci    case DW_AT_GNU_call_site_target_clobbered:
103da0c48c4Sopenharmony_ci      break;
104da0c48c4Sopenharmony_ci
105da0c48c4Sopenharmony_ci    default:
106da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NO_LOC_VALUE);
107da0c48c4Sopenharmony_ci      return false;
108da0c48c4Sopenharmony_ci    }
109da0c48c4Sopenharmony_ci
110da0c48c4Sopenharmony_ci  return true;
111da0c48c4Sopenharmony_ci}
112da0c48c4Sopenharmony_ci
113da0c48c4Sopenharmony_ci
114da0c48c4Sopenharmony_cistruct loclist
115da0c48c4Sopenharmony_ci{
116da0c48c4Sopenharmony_ci  uint8_t atom;
117da0c48c4Sopenharmony_ci  Dwarf_Word number;
118da0c48c4Sopenharmony_ci  Dwarf_Word number2;
119da0c48c4Sopenharmony_ci  Dwarf_Word offset;
120da0c48c4Sopenharmony_ci  struct loclist *next;
121da0c48c4Sopenharmony_ci};
122da0c48c4Sopenharmony_ci
123da0c48c4Sopenharmony_ci
124da0c48c4Sopenharmony_cistatic int
125da0c48c4Sopenharmony_ciloc_compare (const void *p1, const void *p2)
126da0c48c4Sopenharmony_ci{
127da0c48c4Sopenharmony_ci  const struct loc_s *l1 = (const struct loc_s *) p1;
128da0c48c4Sopenharmony_ci  const struct loc_s *l2 = (const struct loc_s *) p2;
129da0c48c4Sopenharmony_ci
130da0c48c4Sopenharmony_ci  if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
131da0c48c4Sopenharmony_ci    return -1;
132da0c48c4Sopenharmony_ci  if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
133da0c48c4Sopenharmony_ci    return 1;
134da0c48c4Sopenharmony_ci
135da0c48c4Sopenharmony_ci  return 0;
136da0c48c4Sopenharmony_ci}
137da0c48c4Sopenharmony_ci
138da0c48c4Sopenharmony_ci/* For each DW_OP_implicit_value, we store a special entry in the cache.
139da0c48c4Sopenharmony_ci   This points us directly to the block data for later fetching.
140da0c48c4Sopenharmony_ci   Returns zero on success, -1 on bad DWARF or 1 if tsearch failed.  */
141da0c48c4Sopenharmony_cistatic int
142da0c48c4Sopenharmony_cistore_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op)
143da0c48c4Sopenharmony_ci{
144da0c48c4Sopenharmony_ci  if (dbg == NULL)
145da0c48c4Sopenharmony_ci    return -1;
146da0c48c4Sopenharmony_ci  struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
147da0c48c4Sopenharmony_ci					   sizeof (struct loc_block_s), 1);
148da0c48c4Sopenharmony_ci  const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2;
149da0c48c4Sopenharmony_ci  /* Skip the block length.  */
150da0c48c4Sopenharmony_ci  Dwarf_Word length;
151da0c48c4Sopenharmony_ci  get_uleb128_unchecked (length, data);
152da0c48c4Sopenharmony_ci  if (length != op->number)
153da0c48c4Sopenharmony_ci    return -1;
154da0c48c4Sopenharmony_ci  block->addr = op;
155da0c48c4Sopenharmony_ci  block->data = (unsigned char *) data;
156da0c48c4Sopenharmony_ci  block->length = op->number;
157da0c48c4Sopenharmony_ci  if (unlikely (tsearch (block, cache, loc_compare) == NULL))
158da0c48c4Sopenharmony_ci    return 1;
159da0c48c4Sopenharmony_ci  return 0;
160da0c48c4Sopenharmony_ci}
161da0c48c4Sopenharmony_ci
162da0c48c4Sopenharmony_ciint
163da0c48c4Sopenharmony_cidwarf_getlocation_implicit_value (Dwarf_Attribute *attr, const Dwarf_Op *op,
164da0c48c4Sopenharmony_ci				  Dwarf_Block *return_block)
165da0c48c4Sopenharmony_ci{
166da0c48c4Sopenharmony_ci  if (attr == NULL)
167da0c48c4Sopenharmony_ci    return -1;
168da0c48c4Sopenharmony_ci
169da0c48c4Sopenharmony_ci  struct loc_block_s fake = { .addr = (void *) op };
170da0c48c4Sopenharmony_ci  struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
171da0c48c4Sopenharmony_ci  if (unlikely (found == NULL))
172da0c48c4Sopenharmony_ci    {
173da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NO_BLOCK);
174da0c48c4Sopenharmony_ci      return -1;
175da0c48c4Sopenharmony_ci    }
176da0c48c4Sopenharmony_ci
177da0c48c4Sopenharmony_ci  return_block->length = (*found)->length;
178da0c48c4Sopenharmony_ci  return_block->data = (*found)->data;
179da0c48c4Sopenharmony_ci  return 0;
180da0c48c4Sopenharmony_ci}
181da0c48c4Sopenharmony_ci
182da0c48c4Sopenharmony_ci/* If the given attribute is DW_AT_data_member_location and it has constant
183da0c48c4Sopenharmony_ci   form then create a fake location using DW_OP_plus_uconst and the offset
184da0c48c4Sopenharmony_ci   value.  On success returns zero and fills in llbuf (when not NULL) and
185da0c48c4Sopenharmony_ci   sets listlen to 1.  Returns 1 when this isn't a DW_AT_data_member_location
186da0c48c4Sopenharmony_ci   offset.  Returns -1 and sets dwarf_errno on failure (bad DWARF data).  */
187da0c48c4Sopenharmony_cistatic int
188da0c48c4Sopenharmony_ciis_constant_offset (Dwarf_Attribute *attr,
189da0c48c4Sopenharmony_ci		    Dwarf_Op **llbuf, size_t *listlen)
190da0c48c4Sopenharmony_ci{
191da0c48c4Sopenharmony_ci  if (attr->code != DW_AT_data_member_location)
192da0c48c4Sopenharmony_ci    return 1;
193da0c48c4Sopenharmony_ci
194da0c48c4Sopenharmony_ci  switch (attr->form)
195da0c48c4Sopenharmony_ci    {
196da0c48c4Sopenharmony_ci      /* Punt for any non-constant form.  */
197da0c48c4Sopenharmony_ci    default:
198da0c48c4Sopenharmony_ci      return 1;
199da0c48c4Sopenharmony_ci
200da0c48c4Sopenharmony_ci      /* Note, we don't regard DW_FORM_data16 as a constant form,
201da0c48c4Sopenharmony_ci	 even though technically it is according to the standard.  */
202da0c48c4Sopenharmony_ci    case DW_FORM_data1:
203da0c48c4Sopenharmony_ci    case DW_FORM_data2:
204da0c48c4Sopenharmony_ci    case DW_FORM_data4:
205da0c48c4Sopenharmony_ci    case DW_FORM_data8:
206da0c48c4Sopenharmony_ci    case DW_FORM_sdata:
207da0c48c4Sopenharmony_ci    case DW_FORM_udata:
208da0c48c4Sopenharmony_ci    case DW_FORM_implicit_const:
209da0c48c4Sopenharmony_ci      break;
210da0c48c4Sopenharmony_ci    }
211da0c48c4Sopenharmony_ci
212da0c48c4Sopenharmony_ci  /* Check whether we already cached this location.  */
213da0c48c4Sopenharmony_ci  struct loc_s fake = { .addr = attr->valp };
214da0c48c4Sopenharmony_ci  struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
215da0c48c4Sopenharmony_ci
216da0c48c4Sopenharmony_ci  if (found == NULL)
217da0c48c4Sopenharmony_ci    {
218da0c48c4Sopenharmony_ci      Dwarf_Word offset;
219da0c48c4Sopenharmony_ci      if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
220da0c48c4Sopenharmony_ci	return -1;
221da0c48c4Sopenharmony_ci
222da0c48c4Sopenharmony_ci      Dwarf_Op *result = libdw_alloc (attr->cu->dbg,
223da0c48c4Sopenharmony_ci				      Dwarf_Op, sizeof (Dwarf_Op), 1);
224da0c48c4Sopenharmony_ci
225da0c48c4Sopenharmony_ci      result->atom = DW_OP_plus_uconst;
226da0c48c4Sopenharmony_ci      result->number = offset;
227da0c48c4Sopenharmony_ci      result->number2 = 0;
228da0c48c4Sopenharmony_ci      result->offset = 0;
229da0c48c4Sopenharmony_ci
230da0c48c4Sopenharmony_ci      /* Insert a record in the search tree so we can find it again later.  */
231da0c48c4Sopenharmony_ci      struct loc_s *newp = libdw_alloc (attr->cu->dbg,
232da0c48c4Sopenharmony_ci					struct loc_s, sizeof (struct loc_s),
233da0c48c4Sopenharmony_ci					1);
234da0c48c4Sopenharmony_ci      newp->addr = attr->valp;
235da0c48c4Sopenharmony_ci      newp->loc = result;
236da0c48c4Sopenharmony_ci      newp->nloc = 1;
237da0c48c4Sopenharmony_ci
238da0c48c4Sopenharmony_ci      found = tsearch (newp, &attr->cu->locs, loc_compare);
239da0c48c4Sopenharmony_ci    }
240da0c48c4Sopenharmony_ci
241da0c48c4Sopenharmony_ci  assert ((*found)->nloc == 1);
242da0c48c4Sopenharmony_ci
243da0c48c4Sopenharmony_ci  if (llbuf != NULL)
244da0c48c4Sopenharmony_ci    {
245da0c48c4Sopenharmony_ci      *llbuf = (*found)->loc;
246da0c48c4Sopenharmony_ci      *listlen = 1;
247da0c48c4Sopenharmony_ci    }
248da0c48c4Sopenharmony_ci
249da0c48c4Sopenharmony_ci  return 0;
250da0c48c4Sopenharmony_ci}
251da0c48c4Sopenharmony_ci
252da0c48c4Sopenharmony_ciint
253da0c48c4Sopenharmony_ciinternal_function
254da0c48c4Sopenharmony_ci__libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
255da0c48c4Sopenharmony_ci			   unsigned int address_size, unsigned int ref_size,
256da0c48c4Sopenharmony_ci			   void **cache, const Dwarf_Block *block,
257da0c48c4Sopenharmony_ci			   bool cfap, bool valuep,
258da0c48c4Sopenharmony_ci			   Dwarf_Op **llbuf, size_t *listlen, int sec_index)
259da0c48c4Sopenharmony_ci{
260da0c48c4Sopenharmony_ci  /* Empty location expressions don't have any ops to intern.  */
261da0c48c4Sopenharmony_ci  if (block->length == 0)
262da0c48c4Sopenharmony_ci    {
263da0c48c4Sopenharmony_ci      *listlen = 0;
264da0c48c4Sopenharmony_ci      return 0;
265da0c48c4Sopenharmony_ci    }
266da0c48c4Sopenharmony_ci
267da0c48c4Sopenharmony_ci  /* Check whether we already looked at this list.  */
268da0c48c4Sopenharmony_ci  struct loc_s fake = { .addr = block->data };
269da0c48c4Sopenharmony_ci  struct loc_s **found = tfind (&fake, cache, loc_compare);
270da0c48c4Sopenharmony_ci  if (found != NULL)
271da0c48c4Sopenharmony_ci    {
272da0c48c4Sopenharmony_ci      /* We already saw it.  */
273da0c48c4Sopenharmony_ci      *llbuf = (*found)->loc;
274da0c48c4Sopenharmony_ci      *listlen = (*found)->nloc;
275da0c48c4Sopenharmony_ci
276da0c48c4Sopenharmony_ci      if (valuep)
277da0c48c4Sopenharmony_ci	{
278da0c48c4Sopenharmony_ci	  assert (*listlen > 1);
279da0c48c4Sopenharmony_ci	  assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value);
280da0c48c4Sopenharmony_ci	}
281da0c48c4Sopenharmony_ci
282da0c48c4Sopenharmony_ci      return 0;
283da0c48c4Sopenharmony_ci    }
284da0c48c4Sopenharmony_ci
285da0c48c4Sopenharmony_ci  const unsigned char *data = block->data;
286da0c48c4Sopenharmony_ci  const unsigned char *const end_data = data + block->length;
287da0c48c4Sopenharmony_ci
288da0c48c4Sopenharmony_ci  const struct { bool other_byte_order; } bo = { other_byte_order };
289da0c48c4Sopenharmony_ci
290da0c48c4Sopenharmony_ci  struct loclist *loclist = NULL;
291da0c48c4Sopenharmony_ci  unsigned int n = 0;
292da0c48c4Sopenharmony_ci
293da0c48c4Sopenharmony_ci  /* Stack allocate at most this many locs.  */
294da0c48c4Sopenharmony_ci#define MAX_STACK_LOCS 256
295da0c48c4Sopenharmony_ci  struct loclist stack_locs[MAX_STACK_LOCS];
296da0c48c4Sopenharmony_ci#define NEW_LOC() ({ struct loclist *ll;			\
297da0c48c4Sopenharmony_ci		     ll = (likely (n < MAX_STACK_LOCS)		\
298da0c48c4Sopenharmony_ci			   ? &stack_locs[n]			\
299da0c48c4Sopenharmony_ci			   : malloc (sizeof (struct loclist)));	\
300da0c48c4Sopenharmony_ci		     if (unlikely (ll == NULL))			\
301da0c48c4Sopenharmony_ci		       goto nomem;				\
302da0c48c4Sopenharmony_ci		     n++;					\
303da0c48c4Sopenharmony_ci		     ll->next = loclist;			\
304da0c48c4Sopenharmony_ci		     loclist = ll;				\
305da0c48c4Sopenharmony_ci		     ll; })
306da0c48c4Sopenharmony_ci
307da0c48c4Sopenharmony_ci  if (cfap)
308da0c48c4Sopenharmony_ci    {
309da0c48c4Sopenharmony_ci      /* Synthesize the operation to push the CFA before the expression.  */
310da0c48c4Sopenharmony_ci      struct loclist *newloc = NEW_LOC ();
311da0c48c4Sopenharmony_ci      newloc->atom = DW_OP_call_frame_cfa;
312da0c48c4Sopenharmony_ci      newloc->number = 0;
313da0c48c4Sopenharmony_ci      newloc->number2 = 0;
314da0c48c4Sopenharmony_ci      newloc->offset = -1;
315da0c48c4Sopenharmony_ci    }
316da0c48c4Sopenharmony_ci
317da0c48c4Sopenharmony_ci  /* Decode the opcodes.  It is possible in some situations to have a
318da0c48c4Sopenharmony_ci     block of size zero.  */
319da0c48c4Sopenharmony_ci  while (data < end_data)
320da0c48c4Sopenharmony_ci    {
321da0c48c4Sopenharmony_ci      struct loclist *newloc;
322da0c48c4Sopenharmony_ci      newloc = NEW_LOC ();
323da0c48c4Sopenharmony_ci      newloc->number = 0;
324da0c48c4Sopenharmony_ci      newloc->number2 = 0;
325da0c48c4Sopenharmony_ci      newloc->offset = data - block->data;
326da0c48c4Sopenharmony_ci
327da0c48c4Sopenharmony_ci      switch ((newloc->atom = *data++))
328da0c48c4Sopenharmony_ci	{
329da0c48c4Sopenharmony_ci	case DW_OP_addr:
330da0c48c4Sopenharmony_ci	  /* Address, depends on address size of CU.  */
331da0c48c4Sopenharmony_ci	  if (dbg == NULL)
332da0c48c4Sopenharmony_ci	    {
333da0c48c4Sopenharmony_ci	      // XXX relocation?
334da0c48c4Sopenharmony_ci	      if (address_size == 4)
335da0c48c4Sopenharmony_ci		{
336da0c48c4Sopenharmony_ci		  if (unlikely (data + 4 > end_data))
337da0c48c4Sopenharmony_ci		    goto invalid;
338da0c48c4Sopenharmony_ci		  else
339da0c48c4Sopenharmony_ci		    newloc->number = read_4ubyte_unaligned_inc (&bo, data);
340da0c48c4Sopenharmony_ci		}
341da0c48c4Sopenharmony_ci	      else
342da0c48c4Sopenharmony_ci		{
343da0c48c4Sopenharmony_ci		  if (unlikely (data + 8 > end_data))
344da0c48c4Sopenharmony_ci		    goto invalid;
345da0c48c4Sopenharmony_ci		  else
346da0c48c4Sopenharmony_ci		    newloc->number = read_8ubyte_unaligned_inc (&bo, data);
347da0c48c4Sopenharmony_ci		}
348da0c48c4Sopenharmony_ci	    }
349da0c48c4Sopenharmony_ci	  else if (__libdw_read_address_inc (dbg, sec_index, &data,
350da0c48c4Sopenharmony_ci					     address_size, &newloc->number))
351da0c48c4Sopenharmony_ci	    goto invalid;
352da0c48c4Sopenharmony_ci	  break;
353da0c48c4Sopenharmony_ci
354da0c48c4Sopenharmony_ci	case DW_OP_call_ref:
355da0c48c4Sopenharmony_ci	case DW_OP_GNU_variable_value:
356da0c48c4Sopenharmony_ci	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
357da0c48c4Sopenharmony_ci	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
358da0c48c4Sopenharmony_ci						      ref_size,
359da0c48c4Sopenharmony_ci						      &newloc->number,
360da0c48c4Sopenharmony_ci						      IDX_debug_info, 0))
361da0c48c4Sopenharmony_ci	    goto invalid;
362da0c48c4Sopenharmony_ci	  break;
363da0c48c4Sopenharmony_ci
364da0c48c4Sopenharmony_ci	case DW_OP_deref:
365da0c48c4Sopenharmony_ci	case DW_OP_dup:
366da0c48c4Sopenharmony_ci	case DW_OP_drop:
367da0c48c4Sopenharmony_ci	case DW_OP_over:
368da0c48c4Sopenharmony_ci	case DW_OP_swap:
369da0c48c4Sopenharmony_ci	case DW_OP_rot:
370da0c48c4Sopenharmony_ci	case DW_OP_xderef:
371da0c48c4Sopenharmony_ci	case DW_OP_abs:
372da0c48c4Sopenharmony_ci	case DW_OP_and:
373da0c48c4Sopenharmony_ci	case DW_OP_div:
374da0c48c4Sopenharmony_ci	case DW_OP_minus:
375da0c48c4Sopenharmony_ci	case DW_OP_mod:
376da0c48c4Sopenharmony_ci	case DW_OP_mul:
377da0c48c4Sopenharmony_ci	case DW_OP_neg:
378da0c48c4Sopenharmony_ci	case DW_OP_not:
379da0c48c4Sopenharmony_ci	case DW_OP_or:
380da0c48c4Sopenharmony_ci	case DW_OP_plus:
381da0c48c4Sopenharmony_ci	case DW_OP_shl:
382da0c48c4Sopenharmony_ci	case DW_OP_shr:
383da0c48c4Sopenharmony_ci	case DW_OP_shra:
384da0c48c4Sopenharmony_ci	case DW_OP_xor:
385da0c48c4Sopenharmony_ci	case DW_OP_eq:
386da0c48c4Sopenharmony_ci	case DW_OP_ge:
387da0c48c4Sopenharmony_ci	case DW_OP_gt:
388da0c48c4Sopenharmony_ci	case DW_OP_le:
389da0c48c4Sopenharmony_ci	case DW_OP_lt:
390da0c48c4Sopenharmony_ci	case DW_OP_ne:
391da0c48c4Sopenharmony_ci	case DW_OP_lit0 ... DW_OP_lit31:
392da0c48c4Sopenharmony_ci	case DW_OP_reg0 ... DW_OP_reg31:
393da0c48c4Sopenharmony_ci	case DW_OP_nop:
394da0c48c4Sopenharmony_ci	case DW_OP_push_object_address:
395da0c48c4Sopenharmony_ci	case DW_OP_call_frame_cfa:
396da0c48c4Sopenharmony_ci	case DW_OP_form_tls_address:
397da0c48c4Sopenharmony_ci	case DW_OP_GNU_push_tls_address:
398da0c48c4Sopenharmony_ci	case DW_OP_stack_value:
399da0c48c4Sopenharmony_ci	  /* No operand.  */
400da0c48c4Sopenharmony_ci	  break;
401da0c48c4Sopenharmony_ci
402da0c48c4Sopenharmony_ci	case DW_OP_const1u:
403da0c48c4Sopenharmony_ci	case DW_OP_pick:
404da0c48c4Sopenharmony_ci	case DW_OP_deref_size:
405da0c48c4Sopenharmony_ci	case DW_OP_xderef_size:
406da0c48c4Sopenharmony_ci	  if (unlikely (data >= end_data))
407da0c48c4Sopenharmony_ci	    {
408da0c48c4Sopenharmony_ci	    invalid:
409da0c48c4Sopenharmony_ci	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
410da0c48c4Sopenharmony_ci	    returnmem:
411da0c48c4Sopenharmony_ci	      /* Free any dynamically allocated loclists, if any.  */
412da0c48c4Sopenharmony_ci	      while (n > MAX_STACK_LOCS)
413da0c48c4Sopenharmony_ci		{
414da0c48c4Sopenharmony_ci		  struct loclist *loc = loclist;
415da0c48c4Sopenharmony_ci		  loclist = loc->next;
416da0c48c4Sopenharmony_ci		  free (loc);
417da0c48c4Sopenharmony_ci		  n--;
418da0c48c4Sopenharmony_ci		}
419da0c48c4Sopenharmony_ci	      return -1;
420da0c48c4Sopenharmony_ci	    }
421da0c48c4Sopenharmony_ci
422da0c48c4Sopenharmony_ci	  newloc->number = *data++;
423da0c48c4Sopenharmony_ci	  break;
424da0c48c4Sopenharmony_ci
425da0c48c4Sopenharmony_ci	case DW_OP_const1s:
426da0c48c4Sopenharmony_ci	  if (unlikely (data >= end_data))
427da0c48c4Sopenharmony_ci	    goto invalid;
428da0c48c4Sopenharmony_ci
429da0c48c4Sopenharmony_ci	  newloc->number = *((int8_t *) data);
430da0c48c4Sopenharmony_ci	  ++data;
431da0c48c4Sopenharmony_ci	  break;
432da0c48c4Sopenharmony_ci
433da0c48c4Sopenharmony_ci	case DW_OP_const2u:
434da0c48c4Sopenharmony_ci	  if (unlikely (data + 2 > end_data))
435da0c48c4Sopenharmony_ci	    goto invalid;
436da0c48c4Sopenharmony_ci
437da0c48c4Sopenharmony_ci	  newloc->number = read_2ubyte_unaligned_inc (&bo, data);
438da0c48c4Sopenharmony_ci	  break;
439da0c48c4Sopenharmony_ci
440da0c48c4Sopenharmony_ci	case DW_OP_const2s:
441da0c48c4Sopenharmony_ci	case DW_OP_skip:
442da0c48c4Sopenharmony_ci	case DW_OP_bra:
443da0c48c4Sopenharmony_ci	case DW_OP_call2:
444da0c48c4Sopenharmony_ci	  if (unlikely (data + 2 > end_data))
445da0c48c4Sopenharmony_ci	    goto invalid;
446da0c48c4Sopenharmony_ci
447da0c48c4Sopenharmony_ci	  newloc->number = read_2sbyte_unaligned_inc (&bo, data);
448da0c48c4Sopenharmony_ci	  break;
449da0c48c4Sopenharmony_ci
450da0c48c4Sopenharmony_ci	case DW_OP_const4u:
451da0c48c4Sopenharmony_ci	  if (unlikely (data + 4 > end_data))
452da0c48c4Sopenharmony_ci	    goto invalid;
453da0c48c4Sopenharmony_ci
454da0c48c4Sopenharmony_ci	  newloc->number = read_4ubyte_unaligned_inc (&bo, data);
455da0c48c4Sopenharmony_ci	  break;
456da0c48c4Sopenharmony_ci
457da0c48c4Sopenharmony_ci	case DW_OP_const4s:
458da0c48c4Sopenharmony_ci	case DW_OP_call4:
459da0c48c4Sopenharmony_ci	case DW_OP_GNU_parameter_ref:
460da0c48c4Sopenharmony_ci	  if (unlikely (data + 4 > end_data))
461da0c48c4Sopenharmony_ci	    goto invalid;
462da0c48c4Sopenharmony_ci
463da0c48c4Sopenharmony_ci	  newloc->number = read_4sbyte_unaligned_inc (&bo, data);
464da0c48c4Sopenharmony_ci	  break;
465da0c48c4Sopenharmony_ci
466da0c48c4Sopenharmony_ci	case DW_OP_const8u:
467da0c48c4Sopenharmony_ci	  if (unlikely (data + 8 > end_data))
468da0c48c4Sopenharmony_ci	    goto invalid;
469da0c48c4Sopenharmony_ci
470da0c48c4Sopenharmony_ci	  newloc->number = read_8ubyte_unaligned_inc (&bo, data);
471da0c48c4Sopenharmony_ci	  break;
472da0c48c4Sopenharmony_ci
473da0c48c4Sopenharmony_ci	case DW_OP_const8s:
474da0c48c4Sopenharmony_ci	  if (unlikely (data + 8 > end_data))
475da0c48c4Sopenharmony_ci	    goto invalid;
476da0c48c4Sopenharmony_ci
477da0c48c4Sopenharmony_ci	  newloc->number = read_8sbyte_unaligned_inc (&bo, data);
478da0c48c4Sopenharmony_ci	  break;
479da0c48c4Sopenharmony_ci
480da0c48c4Sopenharmony_ci	case DW_OP_constu:
481da0c48c4Sopenharmony_ci	case DW_OP_plus_uconst:
482da0c48c4Sopenharmony_ci	case DW_OP_regx:
483da0c48c4Sopenharmony_ci	case DW_OP_piece:
484da0c48c4Sopenharmony_ci	case DW_OP_convert:
485da0c48c4Sopenharmony_ci	case DW_OP_GNU_convert:
486da0c48c4Sopenharmony_ci	case DW_OP_reinterpret:
487da0c48c4Sopenharmony_ci	case DW_OP_GNU_reinterpret:
488da0c48c4Sopenharmony_ci	case DW_OP_addrx:
489da0c48c4Sopenharmony_ci	case DW_OP_GNU_addr_index:
490da0c48c4Sopenharmony_ci	case DW_OP_constx:
491da0c48c4Sopenharmony_ci	case DW_OP_GNU_const_index:
492da0c48c4Sopenharmony_ci	  get_uleb128 (newloc->number, data, end_data);
493da0c48c4Sopenharmony_ci	  break;
494da0c48c4Sopenharmony_ci
495da0c48c4Sopenharmony_ci	case DW_OP_consts:
496da0c48c4Sopenharmony_ci	case DW_OP_breg0 ... DW_OP_breg31:
497da0c48c4Sopenharmony_ci	case DW_OP_fbreg:
498da0c48c4Sopenharmony_ci	  get_sleb128 (newloc->number, data, end_data);
499da0c48c4Sopenharmony_ci	  break;
500da0c48c4Sopenharmony_ci
501da0c48c4Sopenharmony_ci	case DW_OP_bregx:
502da0c48c4Sopenharmony_ci	  get_uleb128 (newloc->number, data, end_data);
503da0c48c4Sopenharmony_ci	  if (unlikely (data >= end_data))
504da0c48c4Sopenharmony_ci	    goto invalid;
505da0c48c4Sopenharmony_ci	  get_sleb128 (newloc->number2, data, end_data);
506da0c48c4Sopenharmony_ci	  break;
507da0c48c4Sopenharmony_ci
508da0c48c4Sopenharmony_ci	case DW_OP_bit_piece:
509da0c48c4Sopenharmony_ci	case DW_OP_regval_type:
510da0c48c4Sopenharmony_ci	case DW_OP_GNU_regval_type:
511da0c48c4Sopenharmony_ci	  get_uleb128 (newloc->number, data, end_data);
512da0c48c4Sopenharmony_ci	  if (unlikely (data >= end_data))
513da0c48c4Sopenharmony_ci	    goto invalid;
514da0c48c4Sopenharmony_ci	  get_uleb128 (newloc->number2, data, end_data);
515da0c48c4Sopenharmony_ci	  break;
516da0c48c4Sopenharmony_ci
517da0c48c4Sopenharmony_ci	case DW_OP_implicit_value:
518da0c48c4Sopenharmony_ci	case DW_OP_entry_value:
519da0c48c4Sopenharmony_ci	case DW_OP_GNU_entry_value:
520da0c48c4Sopenharmony_ci	  /* This cannot be used in a CFI expression.  */
521da0c48c4Sopenharmony_ci	  if (unlikely (dbg == NULL))
522da0c48c4Sopenharmony_ci	    goto invalid;
523da0c48c4Sopenharmony_ci
524da0c48c4Sopenharmony_ci	  /* start of block inc. len.  */
525da0c48c4Sopenharmony_ci	  newloc->number2 = (Dwarf_Word) (uintptr_t) data;
526da0c48c4Sopenharmony_ci	  get_uleb128 (newloc->number, data, end_data); /* Block length.  */
527da0c48c4Sopenharmony_ci	  if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
528da0c48c4Sopenharmony_ci	    goto invalid;
529da0c48c4Sopenharmony_ci	  data += newloc->number;		/* Skip the block.  */
530da0c48c4Sopenharmony_ci	  break;
531da0c48c4Sopenharmony_ci
532da0c48c4Sopenharmony_ci	case DW_OP_implicit_pointer:
533da0c48c4Sopenharmony_ci	case DW_OP_GNU_implicit_pointer:
534da0c48c4Sopenharmony_ci	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
535da0c48c4Sopenharmony_ci	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
536da0c48c4Sopenharmony_ci						      ref_size,
537da0c48c4Sopenharmony_ci						      &newloc->number,
538da0c48c4Sopenharmony_ci						      IDX_debug_info, 0))
539da0c48c4Sopenharmony_ci	    goto invalid;
540da0c48c4Sopenharmony_ci	  if (unlikely (data >= end_data))
541da0c48c4Sopenharmony_ci	    goto invalid;
542da0c48c4Sopenharmony_ci	  get_uleb128 (newloc->number2, data, end_data); /* Byte offset.  */
543da0c48c4Sopenharmony_ci	  break;
544da0c48c4Sopenharmony_ci
545da0c48c4Sopenharmony_ci	case DW_OP_deref_type:
546da0c48c4Sopenharmony_ci	case DW_OP_GNU_deref_type:
547da0c48c4Sopenharmony_ci	case DW_OP_xderef_type:
548da0c48c4Sopenharmony_ci	  if (unlikely (data + 1 >= end_data))
549da0c48c4Sopenharmony_ci	    goto invalid;
550da0c48c4Sopenharmony_ci	  newloc->number = *data++;
551da0c48c4Sopenharmony_ci	  get_uleb128 (newloc->number2, data, end_data);
552da0c48c4Sopenharmony_ci	  break;
553da0c48c4Sopenharmony_ci
554da0c48c4Sopenharmony_ci	case DW_OP_const_type:
555da0c48c4Sopenharmony_ci	case DW_OP_GNU_const_type:
556da0c48c4Sopenharmony_ci	  {
557da0c48c4Sopenharmony_ci	    size_t size;
558da0c48c4Sopenharmony_ci	    get_uleb128 (newloc->number, data, end_data);
559da0c48c4Sopenharmony_ci	    if (unlikely (data >= end_data))
560da0c48c4Sopenharmony_ci	      goto invalid;
561da0c48c4Sopenharmony_ci
562da0c48c4Sopenharmony_ci	    /* start of block inc. len.  */
563da0c48c4Sopenharmony_ci	    newloc->number2 = (Dwarf_Word) (uintptr_t) data;
564da0c48c4Sopenharmony_ci	    size = *data++;
565da0c48c4Sopenharmony_ci	    if (unlikely ((Dwarf_Word) (end_data - data) < size))
566da0c48c4Sopenharmony_ci	      goto invalid;
567da0c48c4Sopenharmony_ci	    data += size;		/* Skip the block.  */
568da0c48c4Sopenharmony_ci	  }
569da0c48c4Sopenharmony_ci	  break;
570da0c48c4Sopenharmony_ci
571da0c48c4Sopenharmony_ci	default:
572da0c48c4Sopenharmony_ci	  goto invalid;
573da0c48c4Sopenharmony_ci	}
574da0c48c4Sopenharmony_ci    }
575da0c48c4Sopenharmony_ci
576da0c48c4Sopenharmony_ci  if (unlikely (n == 0))
577da0c48c4Sopenharmony_ci    {
578da0c48c4Sopenharmony_ci      /* This is not allowed.
579da0c48c4Sopenharmony_ci	 It would mean an empty location expression, which we handled
580da0c48c4Sopenharmony_ci	 already as a special case above.  */
581da0c48c4Sopenharmony_ci      goto invalid;
582da0c48c4Sopenharmony_ci    }
583da0c48c4Sopenharmony_ci
584da0c48c4Sopenharmony_ci  if (valuep)
585da0c48c4Sopenharmony_ci    {
586da0c48c4Sopenharmony_ci      struct loclist *newloc = NEW_LOC ();
587da0c48c4Sopenharmony_ci      newloc->atom = DW_OP_stack_value;
588da0c48c4Sopenharmony_ci      newloc->number = 0;
589da0c48c4Sopenharmony_ci      newloc->number2 = 0;
590da0c48c4Sopenharmony_ci      newloc->offset = data - block->data;
591da0c48c4Sopenharmony_ci    }
592da0c48c4Sopenharmony_ci
593da0c48c4Sopenharmony_ci  /* Allocate the array.  */
594da0c48c4Sopenharmony_ci  Dwarf_Op *result;
595da0c48c4Sopenharmony_ci  if (dbg != NULL)
596da0c48c4Sopenharmony_ci    result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
597da0c48c4Sopenharmony_ci  else
598da0c48c4Sopenharmony_ci    {
599da0c48c4Sopenharmony_ci      result = malloc (sizeof *result * n);
600da0c48c4Sopenharmony_ci      if (result == NULL)
601da0c48c4Sopenharmony_ci	{
602da0c48c4Sopenharmony_ci	nomem:
603da0c48c4Sopenharmony_ci	  __libdw_seterrno (DWARF_E_NOMEM);
604da0c48c4Sopenharmony_ci	  goto returnmem;
605da0c48c4Sopenharmony_ci	}
606da0c48c4Sopenharmony_ci    }
607da0c48c4Sopenharmony_ci
608da0c48c4Sopenharmony_ci  /* Store the result.  */
609da0c48c4Sopenharmony_ci  *llbuf = result;
610da0c48c4Sopenharmony_ci  *listlen = n;
611da0c48c4Sopenharmony_ci
612da0c48c4Sopenharmony_ci  do
613da0c48c4Sopenharmony_ci    {
614da0c48c4Sopenharmony_ci      /* We populate the array from the back since the list is backwards.  */
615da0c48c4Sopenharmony_ci      --n;
616da0c48c4Sopenharmony_ci      result[n].atom = loclist->atom;
617da0c48c4Sopenharmony_ci      result[n].number = loclist->number;
618da0c48c4Sopenharmony_ci      result[n].number2 = loclist->number2;
619da0c48c4Sopenharmony_ci      result[n].offset = loclist->offset;
620da0c48c4Sopenharmony_ci
621da0c48c4Sopenharmony_ci      if (result[n].atom == DW_OP_implicit_value)
622da0c48c4Sopenharmony_ci	{
623da0c48c4Sopenharmony_ci	  int store = store_implicit_value (dbg, cache, &result[n]);
624da0c48c4Sopenharmony_ci	  if (unlikely (store != 0))
625da0c48c4Sopenharmony_ci	    {
626da0c48c4Sopenharmony_ci	      if (store < 0)
627da0c48c4Sopenharmony_ci	        goto invalid;
628da0c48c4Sopenharmony_ci	      else
629da0c48c4Sopenharmony_ci		goto nomem;
630da0c48c4Sopenharmony_ci	    }
631da0c48c4Sopenharmony_ci	}
632da0c48c4Sopenharmony_ci
633da0c48c4Sopenharmony_ci      struct loclist *loc = loclist;
634da0c48c4Sopenharmony_ci      loclist = loclist->next;
635da0c48c4Sopenharmony_ci      if (unlikely (n + 1 > MAX_STACK_LOCS))
636da0c48c4Sopenharmony_ci	free (loc);
637da0c48c4Sopenharmony_ci    }
638da0c48c4Sopenharmony_ci  while (n > 0);
639da0c48c4Sopenharmony_ci
640da0c48c4Sopenharmony_ci  /* Insert a record in the search tree so that we can find it again later.  */
641da0c48c4Sopenharmony_ci  struct loc_s *newp;
642da0c48c4Sopenharmony_ci  if (dbg != NULL)
643da0c48c4Sopenharmony_ci    newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
644da0c48c4Sopenharmony_ci  else
645da0c48c4Sopenharmony_ci    {
646da0c48c4Sopenharmony_ci      newp = malloc (sizeof *newp);
647da0c48c4Sopenharmony_ci      if (newp == NULL)
648da0c48c4Sopenharmony_ci	{
649da0c48c4Sopenharmony_ci	  free (result);
650da0c48c4Sopenharmony_ci	  goto nomem;
651da0c48c4Sopenharmony_ci	}
652da0c48c4Sopenharmony_ci    }
653da0c48c4Sopenharmony_ci
654da0c48c4Sopenharmony_ci  newp->addr = block->data;
655da0c48c4Sopenharmony_ci  newp->loc = result;
656da0c48c4Sopenharmony_ci  newp->nloc = *listlen;
657da0c48c4Sopenharmony_ci  (void) tsearch (newp, cache, loc_compare);
658da0c48c4Sopenharmony_ci
659da0c48c4Sopenharmony_ci  /* We did it.  */
660da0c48c4Sopenharmony_ci  return 0;
661da0c48c4Sopenharmony_ci}
662da0c48c4Sopenharmony_ci
663da0c48c4Sopenharmony_cistatic int
664da0c48c4Sopenharmony_cigetlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
665da0c48c4Sopenharmony_ci	     Dwarf_Op **llbuf, size_t *listlen, int sec_index)
666da0c48c4Sopenharmony_ci{
667da0c48c4Sopenharmony_ci  /* Empty location expressions don't have any ops to intern.
668da0c48c4Sopenharmony_ci     Note that synthetic empty_cu doesn't have an associated DWARF dbg.  */
669da0c48c4Sopenharmony_ci  if (block->length == 0)
670da0c48c4Sopenharmony_ci    {
671da0c48c4Sopenharmony_ci      *listlen = 0;
672da0c48c4Sopenharmony_ci      return 0;
673da0c48c4Sopenharmony_ci    }
674da0c48c4Sopenharmony_ci
675da0c48c4Sopenharmony_ci  return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
676da0c48c4Sopenharmony_ci				    cu->address_size, (cu->version == 2
677da0c48c4Sopenharmony_ci						       ? cu->address_size
678da0c48c4Sopenharmony_ci						       : cu->offset_size),
679da0c48c4Sopenharmony_ci				    &cu->locs, block,
680da0c48c4Sopenharmony_ci				    false, false,
681da0c48c4Sopenharmony_ci				    llbuf, listlen, sec_index);
682da0c48c4Sopenharmony_ci}
683da0c48c4Sopenharmony_ci
684da0c48c4Sopenharmony_ciint
685da0c48c4Sopenharmony_cidwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
686da0c48c4Sopenharmony_ci{
687da0c48c4Sopenharmony_ci  if (! attr_ok (attr))
688da0c48c4Sopenharmony_ci    return -1;
689da0c48c4Sopenharmony_ci
690da0c48c4Sopenharmony_ci  int result = is_constant_offset (attr, llbuf, listlen);
691da0c48c4Sopenharmony_ci  if (result != 1)
692da0c48c4Sopenharmony_ci    return result; /* Either success 0, or -1 to indicate error.  */
693da0c48c4Sopenharmony_ci
694da0c48c4Sopenharmony_ci  /* If it has a block form, it's a single location expression.
695da0c48c4Sopenharmony_ci     Except for DW_FORM_data16, which is a 128bit constant.  */
696da0c48c4Sopenharmony_ci  if (attr->form == DW_FORM_data16)
697da0c48c4Sopenharmony_ci    {
698da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NO_BLOCK);
699da0c48c4Sopenharmony_ci      return -1;
700da0c48c4Sopenharmony_ci    }
701da0c48c4Sopenharmony_ci  Dwarf_Block block;
702da0c48c4Sopenharmony_ci  if (INTUSE(dwarf_formblock) (attr, &block) != 0)
703da0c48c4Sopenharmony_ci    return -1;
704da0c48c4Sopenharmony_ci
705da0c48c4Sopenharmony_ci  return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
706da0c48c4Sopenharmony_ci}
707da0c48c4Sopenharmony_ci
708da0c48c4Sopenharmony_ciDwarf_Addr
709da0c48c4Sopenharmony_ci__libdw_cu_base_address (Dwarf_CU *cu)
710da0c48c4Sopenharmony_ci{
711da0c48c4Sopenharmony_ci  if (cu->base_address == (Dwarf_Addr) -1)
712da0c48c4Sopenharmony_ci    {
713da0c48c4Sopenharmony_ci      Dwarf_Addr base;
714da0c48c4Sopenharmony_ci
715da0c48c4Sopenharmony_ci      /* Fetch the CU's base address.  */
716da0c48c4Sopenharmony_ci      Dwarf_Die cudie = CUDIE (cu);
717da0c48c4Sopenharmony_ci
718da0c48c4Sopenharmony_ci      /* Find the base address of the compilation unit.  It will
719da0c48c4Sopenharmony_ci	 normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
720da0c48c4Sopenharmony_ci	 the base address could be overridden by DW_AT_entry_pc.  It's
721da0c48c4Sopenharmony_ci	 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
722da0c48c4Sopenharmony_ci	 for compilation units with discontinuous ranges.  */
723da0c48c4Sopenharmony_ci      Dwarf_Attribute attr_mem;
724da0c48c4Sopenharmony_ci      if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0
725da0c48c4Sopenharmony_ci	  && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
726da0c48c4Sopenharmony_ci							 DW_AT_entry_pc,
727da0c48c4Sopenharmony_ci							 &attr_mem),
728da0c48c4Sopenharmony_ci				     &base) != 0)
729da0c48c4Sopenharmony_ci	{
730da0c48c4Sopenharmony_ci	  /* The compiler provided no base address when it should
731da0c48c4Sopenharmony_ci	     have.  Buggy GCC does this when it used absolute
732da0c48c4Sopenharmony_ci	     addresses in the location list and no DW_AT_ranges.  */
733da0c48c4Sopenharmony_ci	   base = 0;
734da0c48c4Sopenharmony_ci	}
735da0c48c4Sopenharmony_ci      cu->base_address = base;
736da0c48c4Sopenharmony_ci    }
737da0c48c4Sopenharmony_ci
738da0c48c4Sopenharmony_ci  return cu->base_address;
739da0c48c4Sopenharmony_ci}
740da0c48c4Sopenharmony_ci
741da0c48c4Sopenharmony_cistatic int
742da0c48c4Sopenharmony_ciinitial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
743da0c48c4Sopenharmony_ci{
744da0c48c4Sopenharmony_ci  size_t secidx = (attr->cu->version < 5
745da0c48c4Sopenharmony_ci		   ? IDX_debug_loc : IDX_debug_loclists);
746da0c48c4Sopenharmony_ci
747da0c48c4Sopenharmony_ci  Dwarf_Word start_offset;
748da0c48c4Sopenharmony_ci  if (attr->form == DW_FORM_loclistx)
749da0c48c4Sopenharmony_ci    {
750da0c48c4Sopenharmony_ci      Dwarf_Word idx;
751da0c48c4Sopenharmony_ci      Dwarf_CU *cu = attr->cu;
752da0c48c4Sopenharmony_ci      const unsigned char *datap = attr->valp;
753da0c48c4Sopenharmony_ci      const unsigned char *endp = cu->endp;
754da0c48c4Sopenharmony_ci      if (datap >= endp)
755da0c48c4Sopenharmony_ci	{
756da0c48c4Sopenharmony_ci	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
757da0c48c4Sopenharmony_ci	  return -1;
758da0c48c4Sopenharmony_ci	}
759da0c48c4Sopenharmony_ci      get_uleb128 (idx, datap, endp);
760da0c48c4Sopenharmony_ci
761da0c48c4Sopenharmony_ci      Elf_Data *data = cu->dbg->sectiondata[secidx];
762da0c48c4Sopenharmony_ci      if (data == NULL && cu->unit_type == DW_UT_split_compile)
763da0c48c4Sopenharmony_ci	{
764da0c48c4Sopenharmony_ci	  cu = __libdw_find_split_unit (cu);
765da0c48c4Sopenharmony_ci	  if (cu != NULL)
766da0c48c4Sopenharmony_ci	    data = cu->dbg->sectiondata[secidx];
767da0c48c4Sopenharmony_ci	}
768da0c48c4Sopenharmony_ci
769da0c48c4Sopenharmony_ci      if (data == NULL)
770da0c48c4Sopenharmony_ci	{
771da0c48c4Sopenharmony_ci	  __libdw_seterrno (secidx == IDX_debug_loc
772da0c48c4Sopenharmony_ci                            ? DWARF_E_NO_DEBUG_LOC
773da0c48c4Sopenharmony_ci                            : DWARF_E_NO_DEBUG_LOCLISTS);
774da0c48c4Sopenharmony_ci	  return -1;
775da0c48c4Sopenharmony_ci	}
776da0c48c4Sopenharmony_ci
777da0c48c4Sopenharmony_ci      Dwarf_Off loc_base_off = __libdw_cu_locs_base (cu);
778da0c48c4Sopenharmony_ci
779da0c48c4Sopenharmony_ci      /* The section should at least contain room for one offset.  */
780da0c48c4Sopenharmony_ci      size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
781da0c48c4Sopenharmony_ci      size_t offset_size = cu->offset_size;
782da0c48c4Sopenharmony_ci      if (offset_size > sec_size)
783da0c48c4Sopenharmony_ci	{
784da0c48c4Sopenharmony_ci	invalid_offset:
785da0c48c4Sopenharmony_ci	  __libdw_seterrno (DWARF_E_INVALID_OFFSET);
786da0c48c4Sopenharmony_ci	  return -1;
787da0c48c4Sopenharmony_ci	}
788da0c48c4Sopenharmony_ci
789da0c48c4Sopenharmony_ci      /* And the base offset should be at least inside the section.  */
790da0c48c4Sopenharmony_ci      if (loc_base_off > (sec_size - offset_size))
791da0c48c4Sopenharmony_ci	goto invalid_offset;
792da0c48c4Sopenharmony_ci
793da0c48c4Sopenharmony_ci      size_t max_idx = (sec_size - offset_size - loc_base_off) / offset_size;
794da0c48c4Sopenharmony_ci      if (idx > max_idx)
795da0c48c4Sopenharmony_ci	goto invalid_offset;
796da0c48c4Sopenharmony_ci
797da0c48c4Sopenharmony_ci      datap = (cu->dbg->sectiondata[secidx]->d_buf
798da0c48c4Sopenharmony_ci	       + loc_base_off + (idx * offset_size));
799da0c48c4Sopenharmony_ci      if (offset_size == 4)
800da0c48c4Sopenharmony_ci	start_offset = read_4ubyte_unaligned (cu->dbg, datap);
801da0c48c4Sopenharmony_ci      else
802da0c48c4Sopenharmony_ci	start_offset = read_8ubyte_unaligned (cu->dbg, datap);
803da0c48c4Sopenharmony_ci
804da0c48c4Sopenharmony_ci      start_offset += loc_base_off;
805da0c48c4Sopenharmony_ci    }
806da0c48c4Sopenharmony_ci  else
807da0c48c4Sopenharmony_ci    {
808da0c48c4Sopenharmony_ci      if (__libdw_formptr (attr, secidx,
809da0c48c4Sopenharmony_ci			   (secidx == IDX_debug_loc
810da0c48c4Sopenharmony_ci			    ? DWARF_E_NO_DEBUG_LOC
811da0c48c4Sopenharmony_ci			    : DWARF_E_NO_DEBUG_LOCLISTS),
812da0c48c4Sopenharmony_ci			    NULL, &start_offset) == NULL)
813da0c48c4Sopenharmony_ci	return -1;
814da0c48c4Sopenharmony_ci    }
815da0c48c4Sopenharmony_ci
816da0c48c4Sopenharmony_ci  *offset = start_offset;
817da0c48c4Sopenharmony_ci  return 0;
818da0c48c4Sopenharmony_ci}
819da0c48c4Sopenharmony_ci
820da0c48c4Sopenharmony_cistatic ptrdiff_t
821da0c48c4Sopenharmony_cigetlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
822da0c48c4Sopenharmony_ci		   Dwarf_Addr *basep, Dwarf_Addr *startp, Dwarf_Addr *endp,
823da0c48c4Sopenharmony_ci		   Dwarf_Addr address, const Elf_Data *locs, Dwarf_Op **expr,
824da0c48c4Sopenharmony_ci		   size_t *exprlen)
825da0c48c4Sopenharmony_ci{
826da0c48c4Sopenharmony_ci  Dwarf_CU *cu = attr->cu;
827da0c48c4Sopenharmony_ci  Dwarf *dbg = cu->dbg;
828da0c48c4Sopenharmony_ci  size_t secidx = cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
829da0c48c4Sopenharmony_ci  const unsigned char *readp = locs->d_buf + offset;
830da0c48c4Sopenharmony_ci  const unsigned char *readendp = locs->d_buf + locs->d_size;
831da0c48c4Sopenharmony_ci
832da0c48c4Sopenharmony_ci  Dwarf_Addr begin;
833da0c48c4Sopenharmony_ci  Dwarf_Addr end;
834da0c48c4Sopenharmony_ci
835da0c48c4Sopenharmony_ci next:
836da0c48c4Sopenharmony_ci  switch (__libdw_read_begin_end_pair_inc (cu, secidx,
837da0c48c4Sopenharmony_ci					   &readp, readendp,
838da0c48c4Sopenharmony_ci					   cu->address_size,
839da0c48c4Sopenharmony_ci					   &begin, &end, basep))
840da0c48c4Sopenharmony_ci    {
841da0c48c4Sopenharmony_ci    case 0: /* got location range. */
842da0c48c4Sopenharmony_ci      break;
843da0c48c4Sopenharmony_ci    case 1: /* base address setup. */
844da0c48c4Sopenharmony_ci      goto next;
845da0c48c4Sopenharmony_ci    case 2: /* end of loclist */
846da0c48c4Sopenharmony_ci      return 0;
847da0c48c4Sopenharmony_ci    default: /* error */
848da0c48c4Sopenharmony_ci      return -1;
849da0c48c4Sopenharmony_ci    }
850da0c48c4Sopenharmony_ci
851da0c48c4Sopenharmony_ci  /* We have a location expression.  */
852da0c48c4Sopenharmony_ci  Dwarf_Block block;
853da0c48c4Sopenharmony_ci  if (secidx == IDX_debug_loc)
854da0c48c4Sopenharmony_ci    {
855da0c48c4Sopenharmony_ci      if (readendp - readp < 2)
856da0c48c4Sopenharmony_ci	{
857da0c48c4Sopenharmony_ci	invalid:
858da0c48c4Sopenharmony_ci	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
859da0c48c4Sopenharmony_ci	  return -1;
860da0c48c4Sopenharmony_ci	}
861da0c48c4Sopenharmony_ci      block.length = read_2ubyte_unaligned_inc (dbg, readp);
862da0c48c4Sopenharmony_ci    }
863da0c48c4Sopenharmony_ci  else
864da0c48c4Sopenharmony_ci    {
865da0c48c4Sopenharmony_ci      if (readendp - readp < 1)
866da0c48c4Sopenharmony_ci	goto invalid;
867da0c48c4Sopenharmony_ci      get_uleb128 (block.length, readp, readendp);
868da0c48c4Sopenharmony_ci    }
869da0c48c4Sopenharmony_ci  block.data = (unsigned char *) readp;
870da0c48c4Sopenharmony_ci  if (readendp - readp < (ptrdiff_t) block.length)
871da0c48c4Sopenharmony_ci    goto invalid;
872da0c48c4Sopenharmony_ci  readp += block.length;
873da0c48c4Sopenharmony_ci
874da0c48c4Sopenharmony_ci  /* Note these addresses include any base (if necessary) already.  */
875da0c48c4Sopenharmony_ci  *startp = begin;
876da0c48c4Sopenharmony_ci  *endp = end;
877da0c48c4Sopenharmony_ci
878da0c48c4Sopenharmony_ci  /* If address is minus one we want them all, otherwise only matching.  */
879da0c48c4Sopenharmony_ci  if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp))
880da0c48c4Sopenharmony_ci    goto next;
881da0c48c4Sopenharmony_ci
882da0c48c4Sopenharmony_ci  if (getlocation (cu, &block, expr, exprlen, secidx) != 0)
883da0c48c4Sopenharmony_ci    return -1;
884da0c48c4Sopenharmony_ci
885da0c48c4Sopenharmony_ci  return readp - (unsigned char *) locs->d_buf;
886da0c48c4Sopenharmony_ci}
887da0c48c4Sopenharmony_ci
888da0c48c4Sopenharmony_ciint
889da0c48c4Sopenharmony_cidwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
890da0c48c4Sopenharmony_ci			Dwarf_Op **llbufs, size_t *listlens, size_t maxlocs)
891da0c48c4Sopenharmony_ci{
892da0c48c4Sopenharmony_ci  if (! attr_ok (attr))
893da0c48c4Sopenharmony_ci    return -1;
894da0c48c4Sopenharmony_ci
895da0c48c4Sopenharmony_ci  if (llbufs == NULL)
896da0c48c4Sopenharmony_ci    maxlocs = SIZE_MAX;
897da0c48c4Sopenharmony_ci
898da0c48c4Sopenharmony_ci  /* If it has a block form, it's a single location expression.
899da0c48c4Sopenharmony_ci     Except for DW_FORM_data16, which is a 128bit constant.  */
900da0c48c4Sopenharmony_ci  Dwarf_Block block;
901da0c48c4Sopenharmony_ci  if (attr->form != DW_FORM_data16
902da0c48c4Sopenharmony_ci      && INTUSE(dwarf_formblock) (attr, &block) == 0)
903da0c48c4Sopenharmony_ci    {
904da0c48c4Sopenharmony_ci      if (maxlocs == 0)
905da0c48c4Sopenharmony_ci	return 0;
906da0c48c4Sopenharmony_ci      if (llbufs != NULL &&
907da0c48c4Sopenharmony_ci	  getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
908da0c48c4Sopenharmony_ci		       cu_sec_idx (attr->cu)) != 0)
909da0c48c4Sopenharmony_ci	return -1;
910da0c48c4Sopenharmony_ci      return listlens[0] == 0 ? 0 : 1;
911da0c48c4Sopenharmony_ci    }
912da0c48c4Sopenharmony_ci
913da0c48c4Sopenharmony_ci  if (attr->form != DW_FORM_data16)
914da0c48c4Sopenharmony_ci    {
915da0c48c4Sopenharmony_ci      int error = INTUSE(dwarf_errno) ();
916da0c48c4Sopenharmony_ci      if (unlikely (error != DWARF_E_NO_BLOCK))
917da0c48c4Sopenharmony_ci	{
918da0c48c4Sopenharmony_ci	  __libdw_seterrno (error);
919da0c48c4Sopenharmony_ci	  return -1;
920da0c48c4Sopenharmony_ci	}
921da0c48c4Sopenharmony_ci    }
922da0c48c4Sopenharmony_ci
923da0c48c4Sopenharmony_ci  /* If is_constant_offset is successful, we are done with 1 result.  */
924da0c48c4Sopenharmony_ci  int result = is_constant_offset (attr, llbufs, listlens);
925da0c48c4Sopenharmony_ci  if (result != 1)
926da0c48c4Sopenharmony_ci    return result ?: 1;
927da0c48c4Sopenharmony_ci
928da0c48c4Sopenharmony_ci  Dwarf_Addr base, start, end;
929da0c48c4Sopenharmony_ci  Dwarf_Op *expr;
930da0c48c4Sopenharmony_ci  size_t expr_len;
931da0c48c4Sopenharmony_ci  ptrdiff_t off = 0;
932da0c48c4Sopenharmony_ci  size_t got = 0;
933da0c48c4Sopenharmony_ci
934da0c48c4Sopenharmony_ci  /* This is a true loclistptr, fetch the initial base address and offset.  */
935da0c48c4Sopenharmony_ci  base = __libdw_cu_base_address (attr->cu);
936da0c48c4Sopenharmony_ci  if (base == (Dwarf_Addr) -1)
937da0c48c4Sopenharmony_ci    return -1;
938da0c48c4Sopenharmony_ci
939da0c48c4Sopenharmony_ci  if (initial_offset (attr, &off) != 0)
940da0c48c4Sopenharmony_ci    return -1;
941da0c48c4Sopenharmony_ci
942da0c48c4Sopenharmony_ci  size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
943da0c48c4Sopenharmony_ci  const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
944da0c48c4Sopenharmony_ci
945da0c48c4Sopenharmony_ci  while (got < maxlocs
946da0c48c4Sopenharmony_ci         && (off = getlocations_addr (attr, off, &base, &start, &end,
947da0c48c4Sopenharmony_ci				      address, d, &expr, &expr_len)) > 0)
948da0c48c4Sopenharmony_ci    {
949da0c48c4Sopenharmony_ci      /* This one matches the address.  */
950da0c48c4Sopenharmony_ci      if (llbufs != NULL)
951da0c48c4Sopenharmony_ci	{
952da0c48c4Sopenharmony_ci	  llbufs[got] = expr;
953da0c48c4Sopenharmony_ci	  listlens[got] = expr_len;
954da0c48c4Sopenharmony_ci	}
955da0c48c4Sopenharmony_ci      ++got;
956da0c48c4Sopenharmony_ci    }
957da0c48c4Sopenharmony_ci
958da0c48c4Sopenharmony_ci  /* We might stop early, so off can be zero or positive on success.  */
959da0c48c4Sopenharmony_ci  if (off < 0)
960da0c48c4Sopenharmony_ci    return -1;
961da0c48c4Sopenharmony_ci
962da0c48c4Sopenharmony_ci  return got;
963da0c48c4Sopenharmony_ci}
964da0c48c4Sopenharmony_ci
965da0c48c4Sopenharmony_ciptrdiff_t
966da0c48c4Sopenharmony_cidwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
967da0c48c4Sopenharmony_ci		    Dwarf_Addr *startp, Dwarf_Addr *endp, Dwarf_Op **expr,
968da0c48c4Sopenharmony_ci		    size_t *exprlen)
969da0c48c4Sopenharmony_ci{
970da0c48c4Sopenharmony_ci  if (! attr_ok (attr))
971da0c48c4Sopenharmony_ci    return -1;
972da0c48c4Sopenharmony_ci
973da0c48c4Sopenharmony_ci  /* 1 is an invalid offset, meaning no more locations. */
974da0c48c4Sopenharmony_ci  if (offset == 1)
975da0c48c4Sopenharmony_ci    return 0;
976da0c48c4Sopenharmony_ci
977da0c48c4Sopenharmony_ci  if (offset == 0)
978da0c48c4Sopenharmony_ci    {
979da0c48c4Sopenharmony_ci      /* If it has a block form, it's a single location expression.
980da0c48c4Sopenharmony_ci	 Except for DW_FORM_data16, which is a 128bit constant.  */
981da0c48c4Sopenharmony_ci      Dwarf_Block block;
982da0c48c4Sopenharmony_ci      if (attr->form != DW_FORM_data16
983da0c48c4Sopenharmony_ci	  && INTUSE(dwarf_formblock) (attr, &block) == 0)
984da0c48c4Sopenharmony_ci	{
985da0c48c4Sopenharmony_ci	  if (getlocation (attr->cu, &block, expr, exprlen,
986da0c48c4Sopenharmony_ci			   cu_sec_idx (attr->cu)) != 0)
987da0c48c4Sopenharmony_ci	    return -1;
988da0c48c4Sopenharmony_ci
989da0c48c4Sopenharmony_ci	  /* This is the one and only location covering everything. */
990da0c48c4Sopenharmony_ci	  *startp = 0;
991da0c48c4Sopenharmony_ci	  *endp = -1;
992da0c48c4Sopenharmony_ci	  return 1;
993da0c48c4Sopenharmony_ci	}
994da0c48c4Sopenharmony_ci
995da0c48c4Sopenharmony_ci      if (attr->form != DW_FORM_data16)
996da0c48c4Sopenharmony_ci	{
997da0c48c4Sopenharmony_ci	  int error = INTUSE(dwarf_errno) ();
998da0c48c4Sopenharmony_ci	  if (unlikely (error != DWARF_E_NO_BLOCK))
999da0c48c4Sopenharmony_ci	    {
1000da0c48c4Sopenharmony_ci	      __libdw_seterrno (error);
1001da0c48c4Sopenharmony_ci	      return -1;
1002da0c48c4Sopenharmony_ci	    }
1003da0c48c4Sopenharmony_ci	}
1004da0c48c4Sopenharmony_ci
1005da0c48c4Sopenharmony_ci      int result = is_constant_offset (attr, expr, exprlen);
1006da0c48c4Sopenharmony_ci      if (result != 1)
1007da0c48c4Sopenharmony_ci	{
1008da0c48c4Sopenharmony_ci	  if (result == 0)
1009da0c48c4Sopenharmony_ci	    {
1010da0c48c4Sopenharmony_ci	      /* This is the one and only location covering everything. */
1011da0c48c4Sopenharmony_ci	      *startp = 0;
1012da0c48c4Sopenharmony_ci	      *endp = -1;
1013da0c48c4Sopenharmony_ci	      return 1;
1014da0c48c4Sopenharmony_ci	    }
1015da0c48c4Sopenharmony_ci	  return result; /* Something bad, dwarf_errno has been set.  */
1016da0c48c4Sopenharmony_ci	}
1017da0c48c4Sopenharmony_ci
1018da0c48c4Sopenharmony_ci      /* We must be looking at a true loclistptr, fetch the initial
1019da0c48c4Sopenharmony_ci	 base address and offset.  */
1020da0c48c4Sopenharmony_ci      *basep = __libdw_cu_base_address (attr->cu);
1021da0c48c4Sopenharmony_ci      if (*basep == (Dwarf_Addr) -1)
1022da0c48c4Sopenharmony_ci	return -1;
1023da0c48c4Sopenharmony_ci
1024da0c48c4Sopenharmony_ci      if (initial_offset (attr, &offset) != 0)
1025da0c48c4Sopenharmony_ci	return -1;
1026da0c48c4Sopenharmony_ci    }
1027da0c48c4Sopenharmony_ci
1028da0c48c4Sopenharmony_ci  size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
1029da0c48c4Sopenharmony_ci  const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
1030da0c48c4Sopenharmony_ci
1031da0c48c4Sopenharmony_ci  return getlocations_addr (attr, offset, basep, startp, endp,
1032da0c48c4Sopenharmony_ci			    (Dwarf_Word) -1, d, expr, exprlen);
1033da0c48c4Sopenharmony_ci}
1034