Home | History | Annotate | Download | only in libdw
      1 /* Return sibling of given DIE.
      2    Copyright (C) 2003, 2004 Red Hat, Inc.
      3    Written by Ulrich Drepper <drepper (at) 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
     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