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