• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Get abbreviation at given offset.
2    Copyright (C) 2003, 2004, 2005, 2006, 2014, 2017 Red Hat, Inc.
3    Copyright (C) 2025 Mark J. Wielaard <mark@klomp.org>
4    This file is part of elfutils.
5    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
6 
7    This file is free software; you can redistribute it and/or modify
8    it under the terms of either
9 
10      * the GNU Lesser General Public License as published by the Free
11        Software Foundation; either version 3 of the License, or (at
12        your option) any later version
13 
14    or
15 
16      * the GNU General Public License as published by the Free
17        Software Foundation; either version 2 of the License, or (at
18        your option) any later version
19 
20    or both in parallel, as here.
21 
22    elfutils is distributed in the hope that it will be useful, but
23    WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25    General Public License for more details.
26 
27    You should have received copies of the GNU General Public License and
28    the GNU Lesser General Public License along with this program.  If
29    not, see <http://www.gnu.org/licenses/>.  */
30 
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #include <dwarf.h>
36 #include "libdwP.h"
37 
38 
39 Dwarf_Abbrev *
40 internal_function
__libdw_getabbrev(Dwarf * dbg,struct Dwarf_CU * cu,Dwarf_Off offset,size_t * lengthp)41 __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset,
42 		   size_t *lengthp)
43 {
44   /* Don't fail if there is not .debug_abbrev section.  */
45   if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
46     return NULL;
47 
48   if (offset >= dbg->sectiondata[IDX_debug_abbrev]->d_size)
49     {
50       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
51       return NULL;
52     }
53 
54   const unsigned char *abbrevp
55     = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset;
56 
57   if (*abbrevp == '\0')
58     /* We are past the last entry.  */
59     return DWARF_END_ABBREV;
60 
61   /* 7.5.3 Abbreviations Tables
62 
63      [...] Each declaration begins with an unsigned LEB128 number
64      representing the abbreviation code itself.  [...]  The
65      abbreviation code is followed by another unsigned LEB128
66      number that encodes the entry's tag.  [...]
67 
68      [...] Following the tag encoding is a 1-byte value that
69      determines whether a debugging information entry using this
70      abbreviation has child entries or not. [...]
71 
72      [...] Finally, the child encoding is followed by a series of
73      attribute specifications. Each attribute specification
74      consists of two parts. The first part is an unsigned LEB128
75      number representing the attribute's name. The second part is
76      an unsigned LEB128 number representing the attribute's form.  */
77   const unsigned char *end = (dbg->sectiondata[IDX_debug_abbrev]->d_buf
78 			      + dbg->sectiondata[IDX_debug_abbrev]->d_size);
79   const unsigned char *start_abbrevp = abbrevp;
80   unsigned int code;
81   // We start off with abbrevp at offset, which is checked above.
82   get_uleb128 (code, abbrevp, end);
83 
84   /* Check whether this code is already in the hash table.  */
85   bool foundit = false;
86   Dwarf_Abbrev *abb = NULL;
87   if (cu == NULL
88       || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code)) == NULL)
89     abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
90   else
91     {
92       foundit = true;
93 
94       if (unlikely (abb->offset != offset))
95 	{
96 	  /* A duplicate abbrev code at a different offset,
97 	     that should never happen.  */
98 	invalid:
99 	  if (! foundit)
100 	    libdw_typed_unalloc (dbg, Dwarf_Abbrev);
101 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
102 	  return NULL;
103 	}
104 
105       /* If the caller doesn't need the length we are done.  */
106       if (lengthp == NULL)
107 	goto out;
108     }
109 
110   /* If there is already a value in the hash table we are going to
111      overwrite its content.  This must not be a problem, since the
112      content better be the same.  */
113   abb->code = code;
114   if (abbrevp >= end)
115     goto invalid;
116   get_uleb128 (abb->tag, abbrevp, end);
117   if (abbrevp + 1 >= end)
118     goto invalid;
119   abb->has_children = *abbrevp++ == DW_CHILDREN_yes;
120   abb->attrp = (unsigned char *) abbrevp;
121   abb->offset = offset;
122 
123   /* Skip over all the attributes and check rest of the abbrev is valid.  */
124   unsigned int attrname;
125   unsigned int attrform;
126   do
127     {
128       if (abbrevp >= end)
129 	goto invalid;
130       get_uleb128 (attrname, abbrevp, end);
131       if (abbrevp >= end)
132 	goto invalid;
133       get_uleb128 (attrform, abbrevp, end);
134       if (attrform == DW_FORM_implicit_const)
135 	{
136 	  int64_t formval __attribute__((__unused__));
137 	  if (abbrevp >= end)
138 	    goto invalid;
139 	  get_sleb128 (formval, abbrevp, end);
140 	}
141     }
142   while (attrname != 0 || attrform != 0);
143 
144   /* Return the length to the caller if she asked for it.  */
145   if (lengthp != NULL)
146     *lengthp = abbrevp - start_abbrevp;
147 
148   /* Add the entry to the hash table.  */
149   if (cu != NULL && ! foundit)
150     if (Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb) == -1)
151       {
152 	/* The entry was already in the table, remove the one we just
153 	   created and get the one already inserted.  */
154 	libdw_typed_unalloc (dbg, Dwarf_Abbrev);
155 	abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code);
156       }
157 
158  out:
159   return abb;
160 }
161 
162 
163 Dwarf_Abbrev *
dwarf_getabbrev(Dwarf_Die * die,Dwarf_Off offset,size_t * lengthp)164 dwarf_getabbrev (Dwarf_Die *die, Dwarf_Off offset, size_t *lengthp)
165 {
166   if (die == NULL || die->cu == NULL)
167     return NULL;
168 
169   Dwarf_CU *cu = die->cu;
170   Dwarf *dbg = cu->dbg;
171   Dwarf_Off abbrev_offset = cu->orig_abbrev_offset;
172   Elf_Data *data = dbg->sectiondata[IDX_debug_abbrev];
173   if (data == NULL)
174     return NULL;
175 
176   if (offset >= data->d_size - abbrev_offset)
177     {
178       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
179       return NULL;
180     }
181 
182   return __libdw_getabbrev (dbg, cu, abbrev_offset + offset, lengthp);
183 }
184