Home | History | Annotate | Download | only in libdw
      1 /* Return vhild of current 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 <string.h>
     21 
     22 /* Some arbitrary value not conflicting with any existing code.  */
     23 #define INVALID 0xffffe444
     24 
     25 
     26 unsigned char *
     27 internal_function_def
     28 __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
     29 		   unsigned int *codep, unsigned int *formp)
     30 {
     31   Dwarf *dbg = die->cu->dbg;
     32   unsigned char *readp = (unsigned char *) die->addr;
     33 
     34   /* First we have to get the abbreviation code so that we can decode
     35      the data in the DIE.  */
     36   unsigned int abbrev_code;
     37   get_uleb128 (abbrev_code, readp);
     38 
     39   /* Find the abbreviation entry.  */
     40   Dwarf_Abbrev *abbrevp = die->abbrev;
     41   if (abbrevp == NULL)
     42     {
     43       abbrevp = __libdw_findabbrev (die->cu, abbrev_code);
     44       die->abbrev = abbrevp ?: (Dwarf_Abbrev *) -1l;
     45     }
     46   if (unlikely (die->abbrev == (Dwarf_Abbrev *) -1l))
     47     {
     48       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     49       return NULL;
     50     }
     51 
     52   /* Search the name attribute.  */
     53   unsigned char *const endp
     54     = ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf
     55        + dbg->sectiondata[IDX_debug_abbrev]->d_size);
     56 
     57   unsigned char *attrp = die->abbrev->attrp;
     58   while (1)
     59     {
     60       /* Are we still in bounds?  This test needs to be refined.  */
     61       if (unlikely (attrp + 1 >= endp))
     62 	{
     63 	  __libdw_seterrno (DWARF_E_INVALID_DWARF);
     64 	  return NULL;
     65 	}
     66 
     67       /* Get attribute name and form.
     68 
     69 	 XXX We don't check whether this reads beyond the end of the
     70 	 section.  */
     71       unsigned int attr_name;
     72       get_uleb128 (attr_name, attrp);
     73       unsigned int attr_form;
     74       get_uleb128 (attr_form, attrp);
     75 
     76       /* We can stop if we found the attribute with value zero.  */
     77       if (attr_name == 0 && attr_form == 0)
     78 	break;
     79 
     80       /* Is this the name attribute?  */
     81       if (attr_name == search_name && search_name != INVALID)
     82 	{
     83 	  if (codep != NULL)
     84 	    *codep = attr_name;
     85 	  if (formp != NULL)
     86 	    *formp = attr_form;
     87 
     88 	  return readp;
     89 	}
     90 
     91       /* Skip over the rest of this attribute (if there is any).  */
     92       if (attr_form != 0)
     93 	{
     94 	  size_t len = __libdw_form_val_len (dbg, die->cu, attr_form, readp);
     95 
     96 	  if (unlikely (len == (size_t) -1l))
     97 	    {
     98 	      readp = NULL;
     99 	      break;
    100 	    }
    101 
    102 	  // XXX We need better boundary checks.
    103 	  readp += len;
    104 	}
    105     }
    106 
    107   // XXX Do we need other values?
    108   if (codep != NULL)
    109     *codep = INVALID;
    110   if (formp != NULL)
    111     *formp = INVALID;
    112 
    113   return readp;
    114 }
    115 
    116 
    117 int
    118 dwarf_child (die, result)
    119      Dwarf_Die *die;
    120      Dwarf_Die *result;
    121 {
    122   /* Ignore previous errors.  */
    123   if (die == NULL)
    124     return -1;
    125 
    126   /* Skip past the last attribute.  */
    127   void *addr = NULL;
    128 
    129   /* If we already know there are no children do not search.  */
    130   if (die->abbrev != (Dwarf_Abbrev *) -1
    131       && (die->abbrev == NULL || die->abbrev->has_children))
    132     addr = __libdw_find_attr (die, INVALID, NULL, NULL);
    133   if (die->abbrev == (Dwarf_Abbrev *) -1l)
    134     return -1;
    135 
    136   /* Make sure the DIE really has children.  */
    137   if (! die->abbrev->has_children)
    138     /* There cannot be any children.  */
    139     return 1;
    140 
    141   if (addr == NULL)
    142     return -1;
    143 
    144   /* RESULT can be the same as DIE.  So preserve what we need.  */
    145   struct Dwarf_CU *cu = die->cu;
    146 
    147   /* Clear the entire DIE structure.  This signals we have not yet
    148      determined any of the information.  */
    149   memset (result, '\0', sizeof (Dwarf_Die));
    150 
    151   /* We have the address.  */
    152   result->addr = addr;
    153 
    154   /* Same CU as the parent.  */
    155   result->cu = cu;
    156 
    157   return 0;
    158 }
    159