Line data Source code
1 : /* Find CU for given offset.
2 : Copyright (C) 2003-2010, 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 <assert.h>
35 : #include <search.h>
36 : #include "libdwP.h"
37 :
38 : static int
39 884799 : findcu_cb (const void *arg1, const void *arg2)
40 : {
41 884799 : struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
42 884799 : struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
43 :
44 : /* Find out which of the two arguments is the search value. It has
45 : end offset 0. */
46 884799 : if (cu1->end == 0)
47 : {
48 782662 : if (cu1->start < cu2->start)
49 : return -1;
50 468805 : if (cu1->start >= cu2->end)
51 : return 1;
52 : }
53 : else
54 : {
55 102137 : if (cu2->start < cu1->start)
56 : return 1;
57 0 : if (cu2->start >= cu1->end)
58 : return -1;
59 : }
60 :
61 105711 : return 0;
62 : }
63 :
64 : struct Dwarf_CU *
65 : internal_function
66 10331 : __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
67 : {
68 10331 : Dwarf_Off *const offsetp
69 10331 : = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
70 10331 : void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
71 :
72 10331 : Dwarf_Off oldoff = *offsetp;
73 : uint16_t version;
74 : uint8_t address_size;
75 : uint8_t offset_size;
76 : Dwarf_Off abbrev_offset;
77 10331 : uint64_t type_sig8 = 0;
78 10331 : Dwarf_Off type_offset = 0;
79 :
80 10331 : if (INTUSE(dwarf_next_unit) (dbg, oldoff, offsetp, NULL,
81 : &version, &abbrev_offset,
82 : &address_size, &offset_size,
83 : debug_types ? &type_sig8 : NULL,
84 : debug_types ? &type_offset : NULL) != 0)
85 : /* No more entries. */
86 : return NULL;
87 :
88 : /* We only know how to handle the DWARF version 2 through 4 formats. */
89 10331 : if (unlikely (version < 2) || unlikely (version > 4))
90 : {
91 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
92 0 : return NULL;
93 : }
94 :
95 : /* Invalid or truncated debug section data? */
96 10331 : Elf_Data *data = dbg->sectiondata[debug_types
97 10331 : ? IDX_debug_types : IDX_debug_info];
98 10331 : if (unlikely (*offsetp > data->d_size))
99 0 : *offsetp = data->d_size;
100 :
101 : /* Create an entry for this CU. */
102 10331 : struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
103 :
104 10331 : newp->dbg = dbg;
105 10331 : newp->start = oldoff;
106 10331 : newp->end = *offsetp;
107 10331 : newp->address_size = address_size;
108 10331 : newp->offset_size = offset_size;
109 10331 : newp->version = version;
110 10331 : newp->type_sig8 = type_sig8;
111 10331 : newp->type_offset = type_offset;
112 10331 : Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
113 10331 : newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
114 10331 : newp->lines = NULL;
115 10331 : newp->locs = NULL;
116 :
117 10331 : if (debug_types)
118 4 : Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, type_sig8, newp);
119 :
120 10331 : newp->startp = data->d_buf + newp->start;
121 10331 : newp->endp = data->d_buf + newp->end;
122 :
123 : /* Add the new entry to the search tree. */
124 10331 : if (tsearch (newp, tree, findcu_cb) == NULL)
125 : {
126 : /* Something went wrong. Undo the operation. */
127 0 : *offsetp = oldoff;
128 0 : __libdw_seterrno (DWARF_E_NOMEM);
129 0 : return NULL;
130 : }
131 :
132 : return newp;
133 : }
134 :
135 : struct Dwarf_CU *
136 : internal_function
137 115851 : __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool debug_types)
138 : {
139 115851 : void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
140 115851 : Dwarf_Off *next_offset
141 115851 : = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
142 :
143 : /* Maybe we already know that CU. */
144 115851 : struct Dwarf_CU fake = { .start = start, .end = 0 };
145 115851 : struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
146 115851 : if (found != NULL)
147 105711 : return *found;
148 :
149 10140 : if (start < *next_offset)
150 : {
151 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
152 0 : return NULL;
153 : }
154 :
155 : /* No. Then read more CUs. */
156 : while (1)
157 : {
158 10330 : struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, debug_types);
159 10330 : if (newp == NULL)
160 : return NULL;
161 :
162 : /* Is this the one we are looking for? */
163 10330 : if (start < *next_offset)
164 : // XXX Match exact offset.
165 : return newp;
166 : }
167 : /* NOTREACHED */
168 : }
|