diff options
Diffstat (limited to 'libdwarf/dwarf_next_cu_header.c')
-rw-r--r-- | libdwarf/dwarf_next_cu_header.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/libdwarf/dwarf_next_cu_header.c b/libdwarf/dwarf_next_cu_header.c new file mode 100644 index 00000000..54bb39e3 --- /dev/null +++ b/libdwarf/dwarf_next_cu_header.c @@ -0,0 +1,234 @@ +/* Get offset of next compilation unit. + Copyright (C) 2000, 2002 Red Hat, Inc. + Written by Ulrich Drepper <drepper@redhat.com>, 2000. + + This program is Open Source software; you can redistribute it and/or + modify it under the terms of the Open Software License version 1.0 as + published by the Open Source Initiative. + + You should have received a copy of the Open Software License along + with this program; if not, you may obtain a copy of the Open Software + License version 1.0 from http://www.opensource.org/licenses/osl.php or + by writing the Open Source Initiative c/o Lawrence Rosen, Esq., + 3001 King Ranch Road, Ukiah, CA 95482. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <assert.h> +#include <stdlib.h> + +#include <libdwarfP.h> + + +/* A good initial size for the abbreviation hashing table. */ +#define DEFAULT_ABBREV_HASH_SIZE 257 + + +int +internal_function +__libdwarf_get_cu_at_offset (Dwarf_Debug dbg, Dwarf_Unsigned offset, + Dwarf_CU_Info *result_cu, Dwarf_Error *error) +{ + Dwarf_CU_Info cu; + Dwarf_Small *cu_bytes; + Dwarf_Unsigned length; + Dwarf_Half offset_size; + + /* Make sure there is enough space in the .debug_info section for at + least the initial word. We cannot test the rest since we don't + know yet whether this is a 64-bit object or not. */ + if (unlikely (offset + 4 >= dbg->sections[IDX_debug_info].size)) + { + dbg->cu_list_current = NULL; + return DW_DLV_NO_ENTRY; + } + + /* This points into the .debug_info section to the beginning of the + CU entry. */ + cu_bytes = (Dwarf_Small *) dbg->sections[IDX_debug_info].addr + offset; + + /* The format of the CU header is described in dwarf2p1 7.5.1: + + 1. A 4-byte or 12-byte unsigned integer representing the length + of the .debug_info contribution for that compilation unit, not + including the length field itself. In the 32-bit DWARF format, + this is a 4-byte unsigned integer (which must be less than + 0xffffff00); in the 64-bit DWARF format, this consists of the + 4-byte value 0xffffffff followed by an 8-byte unsigned integer + that gives the actual length (see Section 7.4). + + 2. A 2-byte unsigned integer representing the version of the + DWARF information for that compilation unit. For DWARF Version + 2.1, the value in this field is 2. + + 3. A 4-byte or 8-byte unsigned offset into the .debug_abbrev + section. This offset associates the compilation unit with a + particular set of debugging information entry abbreviations. In + the 32-bit DWARF format, this is a 4-byte unsigned length; in + the 64-bit DWARF format, this is an 8-byte unsigned length (see + Section 7.4). + + 4. A 1-byte unsigned integer representing the size in bytes of + an address on the target architecture. If the system uses + segmented addressing, this value represents the size of the + offset portion of an address. */ + length = read_4ubyte_unaligned (dbg, cu_bytes); + cu_bytes += 4; + offset_size = 4; + if (length == 0xffffffff) + offset_size = 8; + + /* Now we know how large the header is. Note the trick in the + computation. If the offset_size is 4 the '- 4' term undoes the + '2 *'. If offset_size is 8 this term computes the size of the + escape value plus the 8 byte offset. */ + if (unlikely (offset + 2 * offset_size - 4 + sizeof (Dwarf_Half) + + offset_size + sizeof (Dwarf_Small) + >= dbg->sections[IDX_debug_info].size)) + { + dbg->cu_list_current = NULL; + return DW_DLV_NO_ENTRY; + } + + if (length == 0xffffffff) + { + /* This is a 64-bit DWARF format. */ + length = read_8ubyte_unaligned (dbg, cu_bytes); + cu_bytes += 8; + } + + /* We know we have enough room in the .debug_section. Allocate the + result data structure. */ + cu = (Dwarf_CU_Info) malloc (sizeof (struct Dwarf_CU_Info_s)); + if (cu == NULL) + { + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Store the values in the data structure. */ + cu->offset = offset; + cu->offset_size = offset_size; + cu->length = length; + + /* Store the version stamp. Always a 16-bit value. */ + cu->version_stamp = read_2ubyte_unaligned (dbg, cu_bytes); + cu_bytes += 2; + + /* Get offset in .debug_abbrev. Note that the size of the entry + depends on whether this is a 32-bit or 64-bit DWARF definition. */ + if (offset_size == 4) + cu->abbrev_offset = read_4ubyte_unaligned (dbg, cu_bytes); + else + cu->abbrev_offset = read_8ubyte_unaligned (dbg, cu_bytes); + cu_bytes += offset_size; + cu->last_abbrev_offset = cu->abbrev_offset; + + /* The address size. Always an 8-bit value. */ + cu->address_size = *cu_bytes++; + + /* Store the header length. */ + cu->header_length = (cu_bytes + - ((Dwarf_Small *) dbg->sections[IDX_debug_info].addr + + offset)); + + /* Initilize a few more members. */ + if (unlikely (Dwarf_Abbrev_Hash_init (&cu->abbrev_hash, + DEFAULT_ABBREV_HASH_SIZE) != 0)) + { + free (cu); + __libdwarf_error (dbg, error, DW_E_NOMEM); + return DW_DLV_ERROR; + } + + /* Remember the debugging handle. */ + cu->dbg = dbg; + + /* There is no other entry yet. */ + cu->next = NULL; + + /* Enqueue the new entry. */ + if (dbg->cu_list == NULL) + dbg->cu_list = dbg->cu_list_tail = cu; + else + { + dbg->cu_list_tail->next = cu; + dbg->cu_list_tail = cu; + } + *result_cu = cu; + + return DW_DLV_OK; +} + + +int +dwarf_next_cu_header (dbg, cu_header_length, version_stamp, abbrev_offset, + address_size, next_cu_header, error) + Dwarf_Debug dbg; + Dwarf_Unsigned *cu_header_length; + Dwarf_Half *version_stamp; + Dwarf_Unsigned *abbrev_offset; + Dwarf_Half *address_size; + Dwarf_Unsigned *next_cu_header; + Dwarf_Error *error; +{ + Dwarf_Unsigned offset_next_cu; + Dwarf_CU_Info cu; + + if (dbg == NULL) + return DW_DLV_ERROR; + + /* Determine offset of next CU header. If we don't have a current + CU this is the first call and we start right at the beginning. */ + if (dbg->cu_list_current == NULL) + { + offset_next_cu = 0; + cu = dbg->cu_list; + } + else + { + /* We can compute the offset from the information we read from + the last CU header. */ + cu = dbg->cu_list_current; + + offset_next_cu = cu->offset + 2 * cu->offset_size - 4 + cu->length; + + /* See whether the next entry entry is available. */ + cu = cu->next; + } + + /* If the entry is not yet available get it. */ + if (cu == NULL) + { + int res = __libdwarf_get_cu_at_offset (dbg, offset_next_cu, &cu, error); + + /* If it still does not exist, fail. Note that this can mean an + error or that we reached the end. */ + if (res != DW_DLV_OK) + return res; + + dbg->cu_list_current = cu; + assert (cu != NULL); + } + + /* See get_cu_at_offset for an explanation of the trick in this + formula. */ + *next_cu_header = offset_next_cu + 2 * cu->offset_size - 4 + cu->length; + + /* Extract the information and put it where the user wants it. */ + if (cu_header_length != NULL) + *cu_header_length = cu->header_length; + + if (version_stamp != NULL) + *version_stamp = cu->version_stamp; + + if (abbrev_offset != NULL) + *abbrev_offset = cu->abbrev_offset; + + if (address_size != NULL) + *address_size = cu->address_size; + + return DW_DLV_OK; +} |