xref: /third_party/elfutils/libdw/libdw_findcu.c (revision da0c48c4)
1da0c48c4Sopenharmony_ci/* Find CU for given offset.
2da0c48c4Sopenharmony_ci   Copyright (C) 2003-2010, 2014, 2016, 2017, 2018 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
5da0c48c4Sopenharmony_ci
6da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
7da0c48c4Sopenharmony_ci   it under the terms of either
8da0c48c4Sopenharmony_ci
9da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
10da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
11da0c48c4Sopenharmony_ci       your option) any later version
12da0c48c4Sopenharmony_ci
13da0c48c4Sopenharmony_ci   or
14da0c48c4Sopenharmony_ci
15da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
16da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
17da0c48c4Sopenharmony_ci       your option) any later version
18da0c48c4Sopenharmony_ci
19da0c48c4Sopenharmony_ci   or both in parallel, as here.
20da0c48c4Sopenharmony_ci
21da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
22da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
23da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24da0c48c4Sopenharmony_ci   General Public License for more details.
25da0c48c4Sopenharmony_ci
26da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
27da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
28da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
29da0c48c4Sopenharmony_ci
30da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
31da0c48c4Sopenharmony_ci# include <config.h>
32da0c48c4Sopenharmony_ci#endif
33da0c48c4Sopenharmony_ci
34da0c48c4Sopenharmony_ci#include <assert.h>
35da0c48c4Sopenharmony_ci#include <search.h>
36da0c48c4Sopenharmony_ci#include "libdwP.h"
37da0c48c4Sopenharmony_ci
38da0c48c4Sopenharmony_cistatic int
39da0c48c4Sopenharmony_cifindcu_cb (const void *arg1, const void *arg2)
40da0c48c4Sopenharmony_ci{
41da0c48c4Sopenharmony_ci  struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
42da0c48c4Sopenharmony_ci  struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
43da0c48c4Sopenharmony_ci
44da0c48c4Sopenharmony_ci  /* Find out which of the two arguments is the search value.  It has
45da0c48c4Sopenharmony_ci     end offset 0.  */
46da0c48c4Sopenharmony_ci  if (cu1->end == 0)
47da0c48c4Sopenharmony_ci    {
48da0c48c4Sopenharmony_ci      if (cu1->start < cu2->start)
49da0c48c4Sopenharmony_ci	return -1;
50da0c48c4Sopenharmony_ci      if (cu1->start >= cu2->end)
51da0c48c4Sopenharmony_ci	return 1;
52da0c48c4Sopenharmony_ci    }
53da0c48c4Sopenharmony_ci  else
54da0c48c4Sopenharmony_ci    {
55da0c48c4Sopenharmony_ci      if (cu2->start < cu1->start)
56da0c48c4Sopenharmony_ci	return 1;
57da0c48c4Sopenharmony_ci      if (cu2->start >= cu1->end)
58da0c48c4Sopenharmony_ci	return -1;
59da0c48c4Sopenharmony_ci    }
60da0c48c4Sopenharmony_ci
61da0c48c4Sopenharmony_ci  return 0;
62da0c48c4Sopenharmony_ci}
63da0c48c4Sopenharmony_ci
64da0c48c4Sopenharmony_ciint
65da0c48c4Sopenharmony_ci__libdw_finddbg_cb (const void *arg1, const void *arg2)
66da0c48c4Sopenharmony_ci{
67da0c48c4Sopenharmony_ci  Dwarf *dbg1 = (Dwarf *) arg1;
68da0c48c4Sopenharmony_ci  Dwarf *dbg2 = (Dwarf *) arg2;
69da0c48c4Sopenharmony_ci
70da0c48c4Sopenharmony_ci  Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info];
71da0c48c4Sopenharmony_ci  unsigned char *dbg1_start = dbg1_data->d_buf;
72da0c48c4Sopenharmony_ci  size_t dbg1_size = dbg1_data->d_size;
73da0c48c4Sopenharmony_ci
74da0c48c4Sopenharmony_ci  Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info];
75da0c48c4Sopenharmony_ci  unsigned char *dbg2_start = dbg2_data->d_buf;
76da0c48c4Sopenharmony_ci  size_t dbg2_size = dbg2_data->d_size;
77da0c48c4Sopenharmony_ci
78da0c48c4Sopenharmony_ci  /* Find out which of the two arguments is the search value.  It has
79da0c48c4Sopenharmony_ci     a size of 0.  */
80da0c48c4Sopenharmony_ci  if (dbg1_size == 0)
81da0c48c4Sopenharmony_ci    {
82da0c48c4Sopenharmony_ci      if (dbg1_start < dbg2_start)
83da0c48c4Sopenharmony_ci	return -1;
84da0c48c4Sopenharmony_ci      if (dbg1_start >= dbg2_start + dbg2_size)
85da0c48c4Sopenharmony_ci	return 1;
86da0c48c4Sopenharmony_ci    }
87da0c48c4Sopenharmony_ci  else
88da0c48c4Sopenharmony_ci    {
89da0c48c4Sopenharmony_ci      if (dbg2_start < dbg1_start)
90da0c48c4Sopenharmony_ci	return 1;
91da0c48c4Sopenharmony_ci      if (dbg2_start >= dbg1_start + dbg1_size)
92da0c48c4Sopenharmony_ci	return -1;
93da0c48c4Sopenharmony_ci    }
94da0c48c4Sopenharmony_ci
95da0c48c4Sopenharmony_ci  return 0;
96da0c48c4Sopenharmony_ci}
97da0c48c4Sopenharmony_ci
98da0c48c4Sopenharmony_cistruct Dwarf_CU *
99da0c48c4Sopenharmony_ciinternal_function
100da0c48c4Sopenharmony_ci__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
101da0c48c4Sopenharmony_ci{
102da0c48c4Sopenharmony_ci  Dwarf_Off *const offsetp
103da0c48c4Sopenharmony_ci    = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
104da0c48c4Sopenharmony_ci  void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
105da0c48c4Sopenharmony_ci
106da0c48c4Sopenharmony_ci  Dwarf_Off oldoff = *offsetp;
107da0c48c4Sopenharmony_ci  uint16_t version;
108da0c48c4Sopenharmony_ci  uint8_t unit_type;
109da0c48c4Sopenharmony_ci  uint8_t address_size;
110da0c48c4Sopenharmony_ci  uint8_t offset_size;
111da0c48c4Sopenharmony_ci  Dwarf_Off abbrev_offset;
112da0c48c4Sopenharmony_ci  uint64_t unit_id8;
113da0c48c4Sopenharmony_ci  Dwarf_Off subdie_offset;
114da0c48c4Sopenharmony_ci
115da0c48c4Sopenharmony_ci  if (__libdw_next_unit (dbg, debug_types, oldoff, offsetp, NULL,
116da0c48c4Sopenharmony_ci			 &version, &unit_type, &abbrev_offset,
117da0c48c4Sopenharmony_ci			 &address_size, &offset_size,
118da0c48c4Sopenharmony_ci			 &unit_id8, &subdie_offset) != 0)
119da0c48c4Sopenharmony_ci    /* No more entries.  */
120da0c48c4Sopenharmony_ci    return NULL;
121da0c48c4Sopenharmony_ci
122da0c48c4Sopenharmony_ci  /* We only know how to handle the DWARF version 2 through 5 formats.
123da0c48c4Sopenharmony_ci     For v4 debug types we only handle version 4.  */
124da0c48c4Sopenharmony_ci  if (unlikely (version < 2) || unlikely (version > 5)
125da0c48c4Sopenharmony_ci      || (debug_types && unlikely (version != 4)))
126da0c48c4Sopenharmony_ci    {
127da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_VERSION);
128da0c48c4Sopenharmony_ci      return NULL;
129da0c48c4Sopenharmony_ci    }
130da0c48c4Sopenharmony_ci
131da0c48c4Sopenharmony_ci  /* We only handle 32 or 64 bit (4 or 8 byte) addresses and offsets.
132da0c48c4Sopenharmony_ci     Just assume we are dealing with 64bit in case the size is "unknown".
133da0c48c4Sopenharmony_ci     Too much code assumes if it isn't 4 then it is 8 (or the other way
134da0c48c4Sopenharmony_ci     around).  */
135da0c48c4Sopenharmony_ci  if (unlikely (address_size != 4 && address_size != 8))
136da0c48c4Sopenharmony_ci    address_size = 8;
137da0c48c4Sopenharmony_ci  if (unlikely (offset_size != 4 && offset_size != 8))
138da0c48c4Sopenharmony_ci    offset_size = 8;
139da0c48c4Sopenharmony_ci
140da0c48c4Sopenharmony_ci  /* Invalid or truncated debug section data?  */
141da0c48c4Sopenharmony_ci  size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
142da0c48c4Sopenharmony_ci  Elf_Data *data = dbg->sectiondata[sec_idx];
143da0c48c4Sopenharmony_ci  if (unlikely (*offsetp > data->d_size))
144da0c48c4Sopenharmony_ci    *offsetp = data->d_size;
145da0c48c4Sopenharmony_ci
146da0c48c4Sopenharmony_ci  /* Create an entry for this CU.  */
147da0c48c4Sopenharmony_ci  struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
148da0c48c4Sopenharmony_ci
149da0c48c4Sopenharmony_ci  newp->dbg = dbg;
150da0c48c4Sopenharmony_ci  newp->sec_idx = sec_idx;
151da0c48c4Sopenharmony_ci  newp->start = oldoff;
152da0c48c4Sopenharmony_ci  newp->end = *offsetp;
153da0c48c4Sopenharmony_ci  newp->address_size = address_size;
154da0c48c4Sopenharmony_ci  newp->offset_size = offset_size;
155da0c48c4Sopenharmony_ci  newp->version = version;
156da0c48c4Sopenharmony_ci  newp->unit_id8 = unit_id8;
157da0c48c4Sopenharmony_ci  newp->subdie_offset = subdie_offset;
158da0c48c4Sopenharmony_ci  Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
159da0c48c4Sopenharmony_ci  newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
160da0c48c4Sopenharmony_ci  newp->files = NULL;
161da0c48c4Sopenharmony_ci  newp->lines = NULL;
162da0c48c4Sopenharmony_ci  newp->locs = NULL;
163da0c48c4Sopenharmony_ci  newp->split = (Dwarf_CU *) -1;
164da0c48c4Sopenharmony_ci  newp->base_address = (Dwarf_Addr) -1;
165da0c48c4Sopenharmony_ci  newp->addr_base = (Dwarf_Off) -1;
166da0c48c4Sopenharmony_ci  newp->str_off_base = (Dwarf_Off) -1;
167da0c48c4Sopenharmony_ci  newp->ranges_base = (Dwarf_Off) -1;
168da0c48c4Sopenharmony_ci  newp->locs_base = (Dwarf_Off) -1;
169da0c48c4Sopenharmony_ci
170da0c48c4Sopenharmony_ci  newp->startp = data->d_buf + newp->start;
171da0c48c4Sopenharmony_ci  newp->endp = data->d_buf + newp->end;
172da0c48c4Sopenharmony_ci
173da0c48c4Sopenharmony_ci  /* v4 debug type units have version == 4 and unit_type == DW_UT_type.  */
174da0c48c4Sopenharmony_ci  if (debug_types)
175da0c48c4Sopenharmony_ci    newp->unit_type = DW_UT_type;
176da0c48c4Sopenharmony_ci  else if (version < 5)
177da0c48c4Sopenharmony_ci    {
178da0c48c4Sopenharmony_ci      /* This is a reasonable guess (and needed to get the CUDIE).  */
179da0c48c4Sopenharmony_ci      newp->unit_type = DW_UT_compile;
180da0c48c4Sopenharmony_ci
181da0c48c4Sopenharmony_ci      /* But set it correctly from the actual CUDIE tag.  */
182da0c48c4Sopenharmony_ci      Dwarf_Die cudie = CUDIE (newp);
183da0c48c4Sopenharmony_ci      int tag = INTUSE(dwarf_tag) (&cudie);
184da0c48c4Sopenharmony_ci      if (tag == DW_TAG_compile_unit)
185da0c48c4Sopenharmony_ci	{
186da0c48c4Sopenharmony_ci	  Dwarf_Attribute dwo_id;
187da0c48c4Sopenharmony_ci	  if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
188da0c48c4Sopenharmony_ci	    {
189da0c48c4Sopenharmony_ci	      Dwarf_Word id8;
190da0c48c4Sopenharmony_ci	      if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
191da0c48c4Sopenharmony_ci		{
192da0c48c4Sopenharmony_ci		  if (INTUSE(dwarf_haschildren) (&cudie) == 0
193da0c48c4Sopenharmony_ci		      && INTUSE(dwarf_hasattr) (&cudie,
194da0c48c4Sopenharmony_ci						DW_AT_GNU_dwo_name) == 1)
195da0c48c4Sopenharmony_ci		    newp->unit_type = DW_UT_skeleton;
196da0c48c4Sopenharmony_ci		  else
197da0c48c4Sopenharmony_ci		    newp->unit_type = DW_UT_split_compile;
198da0c48c4Sopenharmony_ci
199da0c48c4Sopenharmony_ci		  newp->unit_id8 = id8;
200da0c48c4Sopenharmony_ci		}
201da0c48c4Sopenharmony_ci	    }
202da0c48c4Sopenharmony_ci	}
203da0c48c4Sopenharmony_ci      else if (tag == DW_TAG_partial_unit)
204da0c48c4Sopenharmony_ci	newp->unit_type = DW_UT_partial;
205da0c48c4Sopenharmony_ci      else if (tag == DW_TAG_type_unit)
206da0c48c4Sopenharmony_ci	newp->unit_type = DW_UT_type;
207da0c48c4Sopenharmony_ci    }
208da0c48c4Sopenharmony_ci  else
209da0c48c4Sopenharmony_ci    newp->unit_type = unit_type;
210da0c48c4Sopenharmony_ci
211da0c48c4Sopenharmony_ci  /* Store a reference to any type unit ids in the hash for quick lookup.  */
212da0c48c4Sopenharmony_ci  if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
213da0c48c4Sopenharmony_ci    Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
214da0c48c4Sopenharmony_ci
215da0c48c4Sopenharmony_ci  /* Add the new entry to the search tree.  */
216da0c48c4Sopenharmony_ci  if (tsearch (newp, tree, findcu_cb) == NULL)
217da0c48c4Sopenharmony_ci    {
218da0c48c4Sopenharmony_ci      /* Something went wrong.  Undo the operation.  */
219da0c48c4Sopenharmony_ci      *offsetp = oldoff;
220da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_NOMEM);
221da0c48c4Sopenharmony_ci      return NULL;
222da0c48c4Sopenharmony_ci    }
223da0c48c4Sopenharmony_ci
224da0c48c4Sopenharmony_ci  return newp;
225da0c48c4Sopenharmony_ci}
226da0c48c4Sopenharmony_ci
227da0c48c4Sopenharmony_cistruct Dwarf_CU *
228da0c48c4Sopenharmony_ciinternal_function
229da0c48c4Sopenharmony_ci__libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
230da0c48c4Sopenharmony_ci{
231da0c48c4Sopenharmony_ci  void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
232da0c48c4Sopenharmony_ci  Dwarf_Off *next_offset
233da0c48c4Sopenharmony_ci    = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
234da0c48c4Sopenharmony_ci
235da0c48c4Sopenharmony_ci  /* Maybe we already know that CU.  */
236da0c48c4Sopenharmony_ci  struct Dwarf_CU fake = { .start = start, .end = 0 };
237da0c48c4Sopenharmony_ci  struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
238da0c48c4Sopenharmony_ci  if (found != NULL)
239da0c48c4Sopenharmony_ci    return *found;
240da0c48c4Sopenharmony_ci
241da0c48c4Sopenharmony_ci  if (start < *next_offset)
242da0c48c4Sopenharmony_ci    {
243da0c48c4Sopenharmony_ci      __libdw_seterrno (DWARF_E_INVALID_DWARF);
244da0c48c4Sopenharmony_ci      return NULL;
245da0c48c4Sopenharmony_ci    }
246da0c48c4Sopenharmony_ci
247da0c48c4Sopenharmony_ci  /* No.  Then read more CUs.  */
248da0c48c4Sopenharmony_ci  while (1)
249da0c48c4Sopenharmony_ci    {
250da0c48c4Sopenharmony_ci      struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
251da0c48c4Sopenharmony_ci      if (newp == NULL)
252da0c48c4Sopenharmony_ci	return NULL;
253da0c48c4Sopenharmony_ci
254da0c48c4Sopenharmony_ci      /* Is this the one we are looking for?  */
255da0c48c4Sopenharmony_ci      if (start < *next_offset || start == newp->start)
256da0c48c4Sopenharmony_ci	return newp;
257da0c48c4Sopenharmony_ci    }
258da0c48c4Sopenharmony_ci  /* NOTREACHED */
259da0c48c4Sopenharmony_ci}
260da0c48c4Sopenharmony_ci
261da0c48c4Sopenharmony_cistruct Dwarf_CU *
262da0c48c4Sopenharmony_ciinternal_function
263da0c48c4Sopenharmony_ci__libdw_findcu_addr (Dwarf *dbg, void *addr)
264da0c48c4Sopenharmony_ci{
265da0c48c4Sopenharmony_ci  void **tree;
266da0c48c4Sopenharmony_ci  Dwarf_Off start;
267da0c48c4Sopenharmony_ci  if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
268da0c48c4Sopenharmony_ci      && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
269da0c48c4Sopenharmony_ci		 + dbg->sectiondata[IDX_debug_info]->d_size))
270da0c48c4Sopenharmony_ci    {
271da0c48c4Sopenharmony_ci      tree = &dbg->cu_tree;
272da0c48c4Sopenharmony_ci      start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
273da0c48c4Sopenharmony_ci    }
274da0c48c4Sopenharmony_ci  else if (dbg->sectiondata[IDX_debug_types] != NULL
275da0c48c4Sopenharmony_ci	   && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
276da0c48c4Sopenharmony_ci	   && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
277da0c48c4Sopenharmony_ci		      + dbg->sectiondata[IDX_debug_types]->d_size))
278da0c48c4Sopenharmony_ci    {
279da0c48c4Sopenharmony_ci      tree = &dbg->tu_tree;
280da0c48c4Sopenharmony_ci      start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
281da0c48c4Sopenharmony_ci    }
282da0c48c4Sopenharmony_ci  else
283da0c48c4Sopenharmony_ci    return NULL;
284da0c48c4Sopenharmony_ci
285da0c48c4Sopenharmony_ci  struct Dwarf_CU fake = { .start = start, .end = 0 };
286da0c48c4Sopenharmony_ci  struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
287da0c48c4Sopenharmony_ci
288da0c48c4Sopenharmony_ci  if (found != NULL)
289da0c48c4Sopenharmony_ci    return *found;
290da0c48c4Sopenharmony_ci
291da0c48c4Sopenharmony_ci  return NULL;
292da0c48c4Sopenharmony_ci}
293da0c48c4Sopenharmony_ci
294da0c48c4Sopenharmony_ciDwarf *
295da0c48c4Sopenharmony_ciinternal_function
296da0c48c4Sopenharmony_ci__libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
297da0c48c4Sopenharmony_ci{
298da0c48c4Sopenharmony_ci  /* XXX Assumes split DWARF only has CUs in main IDX_debug_info.  */
299da0c48c4Sopenharmony_ci  Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
300da0c48c4Sopenharmony_ci  Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
301da0c48c4Sopenharmony_ci  Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
302da0c48c4Sopenharmony_ci
303da0c48c4Sopenharmony_ci  if (found != NULL)
304da0c48c4Sopenharmony_ci    return *found;
305da0c48c4Sopenharmony_ci
306da0c48c4Sopenharmony_ci  return NULL;
307da0c48c4Sopenharmony_ci}
308