Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 1 | /* Get abbreviation at given offset. |
| 2 | Copyright (C) 2003, 2004, 2005 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 <assert.h> |
| 20 | #include <dwarf.h> |
| 21 | #include "libdwP.h" |
| 22 | |
| 23 | |
| 24 | Dwarf_Abbrev * |
| 25 | internal_function_def |
| 26 | __libdw_getabbrev (dbg, cu, offset, lengthp, result) |
| 27 | Dwarf *dbg; |
| 28 | struct Dwarf_CU *cu; |
| 29 | Dwarf_Off offset; |
| 30 | size_t *lengthp; |
| 31 | Dwarf_Abbrev *result; |
| 32 | { |
| 33 | /* Don't fail if there is not .debug_abbrev section. */ |
| 34 | if (dbg->sectiondata[IDX_debug_abbrev] == NULL) |
| 35 | return NULL; |
| 36 | |
Roland McGrath | a5a8968 | 2005-08-02 01:24:01 +0000 | [diff] [blame] | 37 | if (offset >= dbg->sectiondata[IDX_debug_abbrev]->d_size) |
| 38 | { |
| 39 | __libdw_seterrno (DWARF_E_INVALID_OFFSET); |
| 40 | return NULL; |
| 41 | } |
| 42 | |
Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 43 | const unsigned char *abbrevp |
| 44 | = (unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf + offset; |
Roland McGrath | a5a8968 | 2005-08-02 01:24:01 +0000 | [diff] [blame] | 45 | |
Ulrich Drepper | b08d5a8 | 2005-07-26 05:00:05 +0000 | [diff] [blame] | 46 | if (*abbrevp == '\0') |
| 47 | /* We are past the last entry. */ |
| 48 | return DWARF_END_ABBREV; |
| 49 | |
| 50 | /* 7.5.3 Abbreviations Tables |
| 51 | |
| 52 | [...] Each declaration begins with an unsigned LEB128 number |
| 53 | representing the abbreviation code itself. [...] The |
| 54 | abbreviation code is followed by another unsigned LEB128 |
| 55 | number that encodes the entry's tag. [...] |
| 56 | |
| 57 | [...] Following the tag encoding is a 1-byte value that |
| 58 | determines whether a debugging information entry using this |
| 59 | abbreviation has child entries or not. [...] |
| 60 | |
| 61 | [...] Finally, the child encoding is followed by a series of |
| 62 | attribute specifications. Each attribute specification |
| 63 | consists of two parts. The first part is an unsigned LEB128 |
| 64 | number representing the attribute's name. The second part is |
| 65 | an unsigned LEB128 number representing the attribute's form. */ |
| 66 | const unsigned char *start_abbrevp = abbrevp; |
| 67 | unsigned int code; |
| 68 | get_uleb128 (code, abbrevp); |
| 69 | |
| 70 | /* Check whether this code is already in the hash table. */ |
| 71 | bool foundit = false; |
| 72 | Dwarf_Abbrev *abb = NULL; |
| 73 | if (cu == NULL |
| 74 | || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL) |
| 75 | { |
| 76 | if (result == NULL) |
| 77 | abb = libdw_typed_alloc (dbg, Dwarf_Abbrev); |
| 78 | else |
| 79 | abb = result; |
| 80 | } |
| 81 | else |
| 82 | { |
| 83 | foundit = true; |
| 84 | |
| 85 | assert (abb->offset == offset); |
| 86 | |
| 87 | /* If the caller doesn't need the length we are done. */ |
| 88 | if (lengthp == NULL) |
| 89 | goto out; |
| 90 | } |
| 91 | |
| 92 | /* If there is already a value in the hash table we are going to |
| 93 | overwrite its content. This must not be a problem, since the |
| 94 | content better be the same. */ |
| 95 | abb->code = code; |
| 96 | get_uleb128 (abb->tag, abbrevp); |
| 97 | abb->has_children = *abbrevp++ == DW_CHILDREN_yes; |
| 98 | abb->attrp = (unsigned char *) abbrevp; |
| 99 | abb->offset = offset; |
| 100 | |
| 101 | /* Skip over all the attributes and count them while doing so. */ |
| 102 | abb->attrcnt = 0; |
| 103 | unsigned int attrname; |
| 104 | unsigned int attrform; |
| 105 | do |
| 106 | { |
| 107 | get_uleb128 (attrname, abbrevp); |
| 108 | get_uleb128 (attrform, abbrevp); |
| 109 | } |
| 110 | while (attrname != 0 && attrform != 0 && ++abb->attrcnt); |
| 111 | |
| 112 | /* Return the length to the caller if she asked for it. */ |
| 113 | if (lengthp != NULL) |
| 114 | *lengthp = abbrevp - start_abbrevp; |
| 115 | |
| 116 | /* Add the entry to the hash table. */ |
| 117 | if (cu != NULL && ! foundit) |
| 118 | (void) Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb); |
| 119 | |
| 120 | out: |
| 121 | return abb; |
| 122 | } |
| 123 | |
| 124 | |
| 125 | Dwarf_Abbrev * |
| 126 | dwarf_getabbrev (die, offset, lengthp) |
| 127 | Dwarf_Die *die; |
| 128 | Dwarf_Off offset; |
| 129 | size_t *lengthp; |
| 130 | { |
| 131 | return __libdw_getabbrev (die->cu->dbg, die->cu, |
| 132 | die->cu->orig_abbrev_offset + offset, lengthp, |
| 133 | NULL); |
| 134 | } |