1 /* $NetBSD: libdwarf_die.c,v 1.2 2014/03/09 16:58:04 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2007 John Birrell (jb@freebsd.org)
5 * Copyright (c) 2009-2011 Kai Wang
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include "_libdwarf.h"
31
32 __RCSID("$NetBSD: libdwarf_die.c,v 1.2 2014/03/09 16:58:04 christos Exp $");
33 ELFTC_VCSID("Id: libdwarf_die.c 2948 2013-05-30 21:25:52Z kaiwang27 ");
34
35 int
_dwarf_die_alloc(Dwarf_Debug dbg,Dwarf_Die * ret_die,Dwarf_Error * error)36 _dwarf_die_alloc(Dwarf_Debug dbg, Dwarf_Die *ret_die, Dwarf_Error *error)
37 {
38 Dwarf_Die die;
39
40 assert(ret_die != NULL);
41
42 if ((die = calloc(1, sizeof(struct _Dwarf_Die))) == NULL) {
43 DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
44 return (DW_DLE_MEMORY);
45 }
46
47 STAILQ_INIT(&die->die_attr);
48
49 *ret_die = die;
50
51 return (DW_DLE_NONE);
52 }
53
54 static int
_dwarf_die_add(Dwarf_CU cu,uint64_t offset,uint64_t abnum,Dwarf_Abbrev ab,Dwarf_Die * diep,Dwarf_Error * error)55 _dwarf_die_add(Dwarf_CU cu, uint64_t offset, uint64_t abnum, Dwarf_Abbrev ab,
56 Dwarf_Die *diep, Dwarf_Error *error)
57 {
58 Dwarf_Debug dbg;
59 Dwarf_Die die;
60 int ret;
61
62 assert(cu != NULL);
63 assert(ab != NULL);
64
65 dbg = cu->cu_dbg;
66
67 if ((ret = _dwarf_die_alloc(dbg, &die, error)) != DW_DLE_NONE)
68 return (ret);
69
70 die->die_offset = offset;
71 die->die_abnum = abnum;
72 die->die_ab = ab;
73 die->die_cu = cu;
74 die->die_dbg = cu->cu_dbg;
75
76 if (diep != NULL)
77 *diep = die;
78
79 return (DW_DLE_NONE);
80 }
81
82 /* Find die at offset 'off' within the same CU. */
83 Dwarf_Die
_dwarf_die_find(Dwarf_Die die,Dwarf_Unsigned off)84 _dwarf_die_find(Dwarf_Die die, Dwarf_Unsigned off)
85 {
86 Dwarf_Debug dbg;
87 Dwarf_CU cu;
88 Dwarf_Die die1;
89 Dwarf_Error de;
90 int ret;
91
92 cu = die->die_cu;
93 dbg = die->die_dbg;
94
95 ret = _dwarf_die_parse(dbg, dbg->dbg_info_sec, cu, cu->cu_dwarf_size,
96 off, cu->cu_next_offset, &die1, 0, &de);
97
98 if (ret == DW_DLE_NONE)
99 return (die1);
100 else
101 return (NULL);
102 }
103
104 int
_dwarf_die_parse(Dwarf_Debug dbg,Dwarf_Section * ds,Dwarf_CU cu,int dwarf_size,uint64_t offset,uint64_t next_offset,Dwarf_Die * ret_die,int search_sibling,Dwarf_Error * error)105 _dwarf_die_parse(Dwarf_Debug dbg, Dwarf_Section *ds, Dwarf_CU cu,
106 int dwarf_size, uint64_t offset, uint64_t next_offset, Dwarf_Die *ret_die,
107 int search_sibling, Dwarf_Error *error)
108 {
109 Dwarf_Abbrev ab;
110 Dwarf_AttrDef ad;
111 Dwarf_Die die;
112 uint64_t abnum;
113 uint64_t die_offset;
114 int ret, level;
115
116 assert(cu != NULL);
117
118 level = 1;
119 die = NULL;
120
121 while (offset < next_offset && offset < ds->ds_size) {
122
123 die_offset = offset;
124
125 abnum = _dwarf_read_uleb128(ds->ds_data, &offset);
126
127 if (abnum == 0) {
128 if (level == 0 || !search_sibling)
129 return (DW_DLE_NO_ENTRY);
130
131 /*
132 * Return to previous DIE level.
133 */
134 level--;
135 continue;
136 }
137
138 if ((ret = _dwarf_abbrev_find(cu, abnum, &ab, error)) !=
139 DW_DLE_NONE)
140 return (ret);
141
142 if ((ret = _dwarf_die_add(cu, die_offset, abnum, ab, &die,
143 error)) != DW_DLE_NONE)
144 return (ret);
145
146 STAILQ_FOREACH(ad, &ab->ab_attrdef, ad_next) {
147 if ((ret = _dwarf_attr_init(dbg, ds, &offset,
148 dwarf_size, cu, die, ad, ad->ad_form, 0,
149 error)) != DW_DLE_NONE)
150 return (ret);
151 }
152
153 die->die_next_off = offset;
154 if (search_sibling && level > 0) {
155 dwarf_dealloc(dbg, die, DW_DLA_DIE);
156 if (ab->ab_children == DW_CHILDREN_yes) {
157 /* Advance to next DIE level. */
158 level++;
159 }
160 } else {
161 *ret_die = die;
162 return (DW_DLE_NONE);
163 }
164 }
165
166 return (DW_DLE_NO_ENTRY);
167 }
168
169 void
_dwarf_die_link(Dwarf_P_Die die,Dwarf_P_Die parent,Dwarf_P_Die child,Dwarf_P_Die left_sibling,Dwarf_P_Die right_sibling)170 _dwarf_die_link(Dwarf_P_Die die, Dwarf_P_Die parent, Dwarf_P_Die child,
171 Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling)
172 {
173 Dwarf_P_Die last_child;
174
175 assert(die != NULL);
176
177 if (parent) {
178
179 /* Disconnect from old parent. */
180 if (die->die_parent) {
181 if (die->die_parent != parent) {
182 if (die->die_parent->die_child == die)
183 die->die_parent->die_child = NULL;
184 die->die_parent = NULL;
185 }
186 }
187
188 /* Find the last child of this parent. */
189 last_child = parent->die_child;
190 if (last_child) {
191 while (last_child->die_right != NULL)
192 last_child = last_child->die_right;
193 }
194
195 /* Connect to new parent. */
196 die->die_parent = parent;
197
198 /*
199 * Attach this DIE to the end of sibling list. If new
200 * parent doesn't have any child, set this DIE as the
201 * first child.
202 */
203 if (last_child) {
204 assert(last_child->die_right == NULL);
205 last_child->die_right = die;
206 die->die_left = last_child;
207 } else
208 parent->die_child = die;
209 }
210
211 if (child) {
212
213 /* Disconnect from old child. */
214 if (die->die_child) {
215 if (die->die_child != child) {
216 die->die_child->die_parent = NULL;
217 die->die_child = NULL;
218 }
219 }
220
221 /* Connect to new child. */
222 die->die_child = child;
223 child->die_parent = die;
224 }
225
226 if (left_sibling) {
227
228 /* Disconnect from old left sibling. */
229 if (die->die_left) {
230 if (die->die_left != left_sibling) {
231 die->die_left->die_right = NULL;
232 die->die_left = NULL;
233 }
234 }
235
236 /* Connect to new right sibling. */
237 die->die_left = left_sibling;
238 left_sibling->die_right = die;
239 }
240
241 if (right_sibling) {
242
243 /* Disconnect from old right sibling. */
244 if (die->die_right) {
245 if (die->die_right != right_sibling) {
246 die->die_right->die_left = NULL;
247 die->die_right = NULL;
248 }
249 }
250
251 /* Connect to new right sibling. */
252 die->die_right = right_sibling;
253 right_sibling->die_left = die;
254 }
255 }
256
257 int
_dwarf_die_count_links(Dwarf_P_Die parent,Dwarf_P_Die child,Dwarf_P_Die left_sibling,Dwarf_P_Die right_sibling)258 _dwarf_die_count_links(Dwarf_P_Die parent, Dwarf_P_Die child,
259 Dwarf_P_Die left_sibling, Dwarf_P_Die right_sibling)
260 {
261 int count;
262
263 count = 0;
264
265 if (parent)
266 count++;
267 if (child)
268 count++;
269 if (left_sibling)
270 count++;
271 if (right_sibling)
272 count++;
273
274 return (count);
275 }
276
277 static int
_dwarf_die_gen_recursive(Dwarf_P_Debug dbg,Dwarf_CU cu,Dwarf_Rel_Section drs,Dwarf_P_Die die,int pass2,Dwarf_Error * error)278 _dwarf_die_gen_recursive(Dwarf_P_Debug dbg, Dwarf_CU cu, Dwarf_Rel_Section drs,
279 Dwarf_P_Die die, int pass2, Dwarf_Error *error)
280 {
281 Dwarf_P_Section ds;
282 Dwarf_Abbrev ab;
283 Dwarf_Attribute at;
284 Dwarf_AttrDef ad;
285 int match, ret;
286
287 ds = dbg->dbgp_info;
288 assert(ds != NULL);
289
290 if (pass2)
291 goto attr_gen;
292
293 /*
294 * Add DW_AT_sibling attribute for DIEs with children, so consumers
295 * can quickly scan chains of siblings, while ignoring the children
296 * of individual siblings.
297 */
298 if (die->die_child && die->die_right) {
299 if (_dwarf_attr_find(die, DW_AT_sibling) == NULL)
300 (void) dwarf_add_AT_reference(dbg, die, DW_AT_sibling,
301 die->die_right, error);
302 }
303
304 /*
305 * Search abbrev list to find a matching entry.
306 */
307 die->die_ab = NULL;
308 for (ab = cu->cu_abbrev_hash; ab != NULL; ab = ab->ab_hh.next) {
309 if (die->die_tag != ab->ab_tag)
310 continue;
311 if (ab->ab_children == DW_CHILDREN_no && die->die_child != NULL)
312 continue;
313 if (ab->ab_children == DW_CHILDREN_yes &&
314 die->die_child == NULL)
315 continue;
316 at = STAILQ_FIRST(&die->die_attr);
317 ad = STAILQ_FIRST(&ab->ab_attrdef);
318 match = 1;
319 while (at != NULL && ad != NULL) {
320 if (at->at_attrib != ad->ad_attrib ||
321 at->at_form != ad->ad_form) {
322 match = 0;
323 break;
324 }
325 at = STAILQ_NEXT(at, at_next);
326 ad = STAILQ_NEXT(ad, ad_next);
327 }
328 if ((at == NULL && ad != NULL) || (at != NULL && ad == NULL))
329 match = 0;
330 if (match) {
331 die->die_ab = ab;
332 break;
333 }
334 }
335
336 /*
337 * Create a new abbrev entry if we can not reuse any existing one.
338 */
339 if (die->die_ab == NULL) {
340 ret = _dwarf_abbrev_add(cu, ++cu->cu_abbrev_cnt, die->die_tag,
341 die->die_child != NULL ? DW_CHILDREN_yes : DW_CHILDREN_no,
342 0, &ab, error);
343 if (ret != DW_DLE_NONE)
344 return (ret);
345 STAILQ_FOREACH(at, &die->die_attr, at_next) {
346 ret = _dwarf_attrdef_add(dbg, ab, at->at_attrib,
347 at->at_form, 0, NULL, error);
348 if (ret != DW_DLE_NONE)
349 return (ret);
350 }
351 die->die_ab = ab;
352 }
353
354 die->die_offset = ds->ds_size;
355
356 /*
357 * Transform the DIE to bytes stream.
358 */
359 ret = _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap,
360 &ds->ds_size, die->die_ab->ab_entry, error);
361 if (ret != DW_DLE_NONE)
362 return (ret);
363
364 attr_gen:
365
366 /* Transform the attributes of this DIE. */
367 ret = _dwarf_attr_gen(dbg, ds, drs, cu, die, pass2, error);
368 if (ret != DW_DLE_NONE)
369 return (ret);
370
371 /* Proceed to child DIE. */
372 if (die->die_child != NULL) {
373 ret = _dwarf_die_gen_recursive(dbg, cu, drs, die->die_child,
374 pass2, error);
375 if (ret != DW_DLE_NONE)
376 return (ret);
377 }
378
379 /* Proceed to sibling DIE. */
380 if (die->die_right != NULL) {
381 ret = _dwarf_die_gen_recursive(dbg, cu, drs, die->die_right,
382 pass2, error);
383 if (ret != DW_DLE_NONE)
384 return (ret);
385 }
386
387 /* Write a null DIE indicating the end of current level. */
388 if (die->die_right == NULL) {
389 ret = _dwarf_write_uleb128_alloc(&ds->ds_data, &ds->ds_cap,
390 &ds->ds_size, 0, error);
391 if (ret != DW_DLE_NONE)
392 return (ret);
393 }
394
395 return (DW_DLE_NONE);
396 }
397
398 int
_dwarf_die_gen(Dwarf_P_Debug dbg,Dwarf_CU cu,Dwarf_Rel_Section drs,Dwarf_Error * error)399 _dwarf_die_gen(Dwarf_P_Debug dbg, Dwarf_CU cu, Dwarf_Rel_Section drs,
400 Dwarf_Error *error)
401 {
402 Dwarf_Abbrev ab, tab;
403 Dwarf_AttrDef ad, tad;
404 Dwarf_Die die;
405 int ret;
406
407 assert(dbg != NULL && cu != NULL);
408 assert(dbg->dbgp_root_die != NULL);
409
410 die = dbg->dbgp_root_die;
411
412 /*
413 * Insert a DW_AT_stmt_list attribute into root DIE, if there are
414 * line number information.
415 */
416 if (!STAILQ_EMPTY(&dbg->dbgp_lineinfo->li_lnlist))
417 RCHECK(_dwarf_add_AT_dataref(dbg, die, DW_AT_stmt_list, 0, 0,
418 ".debug_line", NULL, error));
419
420 RCHECK(_dwarf_die_gen_recursive(dbg, cu, drs, die, 0, error));
421
422 if (cu->cu_pass2)
423 RCHECK(_dwarf_die_gen_recursive(dbg, cu, drs, die, 1, error));
424
425 return (DW_DLE_NONE);
426
427 gen_fail:
428
429 HASH_ITER(ab_hh, cu->cu_abbrev_hash, ab, tab) {
430 HASH_DELETE(ab_hh, cu->cu_abbrev_hash, ab);
431 STAILQ_FOREACH_SAFE(ad, &ab->ab_attrdef, ad_next, tad) {
432 STAILQ_REMOVE(&ab->ab_attrdef, ad, _Dwarf_AttrDef,
433 ad_next);
434 free(ad);
435 }
436 free(ab);
437 }
438
439 return (ret);
440 }
441
442 void
_dwarf_die_pro_cleanup(Dwarf_P_Debug dbg)443 _dwarf_die_pro_cleanup(Dwarf_P_Debug dbg)
444 {
445 Dwarf_P_Die die, tdie;
446 Dwarf_P_Attribute at, tat;
447
448 assert(dbg != NULL && dbg->dbg_mode == DW_DLC_WRITE);
449
450 STAILQ_FOREACH_SAFE(die, &dbg->dbgp_dielist, die_pro_next, tdie) {
451 STAILQ_FOREACH_SAFE(at, &die->die_attr, at_next, tat) {
452 STAILQ_REMOVE(&die->die_attr, at, _Dwarf_Attribute,
453 at_next);
454 free(at);
455 }
456 free(die);
457 }
458 }
459