1 /* Return sibling of given DIE.
2 Copyright (C) 2003, 2004 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2003.
4
5 This program is Open Source software; you can redistribute it and/or
6 modify it under the terms of the Open Software License version 1.0 as
7 published by the Open Source Initiative.
8
9 You should have received a copy of the Open Software License along
10 with this program; if not, you may obtain a copy of the Open Software
11 License version 1.0 from http://www.opensource.org/licenses/osl.php or
12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13 3001 King Ranch Road, Ukiah, CA 95482. */
14
15 #ifdef HAVE_CONFIG_H
16 # include <config.h>
17 #endif
18
19 #include "libdwP.h"
20 #include <dwarf.h>
21 #include <string.h>
22
23
24 int
dwarf_siblingof(die,result)25 dwarf_siblingof (die, result)
26 Dwarf_Die *die;
27 Dwarf_Die *result;
28 {
29 /* Ignore previous errors. */
30 if (die == NULL)
31 return -1;
32
33 unsigned int level = 0;
34
35 /* Copy of the current DIE. */
36 Dwarf_Die this_die = *die;
37 /* Temporary attributes we create. */
38 Dwarf_Attribute sibattr;
39 /* Copy of the CU in the request. */
40 sibattr.cu = this_die.cu;
41 /* That's the address we start looking. */
42 unsigned char *addr = this_die.addr;
43
44 /* Search for the beginning of the next die on this level. We
45 must not return the dies for children of the given die. */
46 do
47 {
48 /* Find the end of the DIE or the sibling attribute. */
49 addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code,
50 &sibattr.form);
51 if (sibattr.code == DW_AT_sibling)
52 {
53 Dwarf_Off offset;
54 sibattr.valp = addr;
55 if (dwarf_formref (&sibattr, &offset) != 0)
56 /* Something went wrong. */
57 return -1;
58
59 /* Compute the next address. */
60 addr = ((unsigned char *)
61 sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf
62 + sibattr.cu->start + offset);
63 }
64 else if (unlikely (addr == NULL)
65 || unlikely (this_die.abbrev == (Dwarf_Abbrev *) -1l))
66 return -1;
67 else if (this_die.abbrev->has_children)
68 /* This abbreviation has children. */
69 ++level;
70
71 /* Check that we are not yet at the end. */
72 while (*addr == '\0')
73 {
74 if (level-- == 0)
75 /* No more sibling at all. */
76 return 1;
77
78 ++addr;
79 }
80
81 /* Initialize the 'current DIE'. */
82 this_die.addr = addr;
83 this_die.abbrev = NULL;
84 }
85 while (level > 0);
86
87 /* Maybe we reached the end of the CU. */
88 if (addr
89 >= ((unsigned char *) sibattr.cu->dbg->sectiondata[IDX_debug_info]->d_buf
90 + sibattr.cu->end))
91 return 1;
92
93 /* Clear the entire DIE structure. This signals we have not yet
94 determined any of the information. */
95 memset (result, '\0', sizeof (Dwarf_Die));
96
97 /* We have the address. */
98 result->addr = addr;
99
100 /* Same CU as the parent. */
101 result->cu = sibattr.cu;
102
103 return 0;
104 }
105