diff options
| author | Richard Lowe <richlowe@richlowe.net> | 2011-05-22 03:13:22 +0100 |
|---|---|---|
| committer | Richard Lowe <richlowe@richlowe.net> | 2011-06-29 19:12:22 -0400 |
| commit | 77b6d4a80fc05587b08370de690c979abe2667d5 (patch) | |
| tree | f00c511c215afecbbe09aac179e10839099358a6 /usr/src/tools/ctf/dwarf/common/dwarf_global.c | |
| parent | 9ecc7612020c1993e4dbadd3422a74b210279739 (diff) | |
| download | illumos-joyent-77b6d4a80fc05587b08370de690c979abe2667d5.tar.gz | |
dwarf: Upgrade to libdwarf-20110113
Diffstat (limited to 'usr/src/tools/ctf/dwarf/common/dwarf_global.c')
| -rw-r--r-- | usr/src/tools/ctf/dwarf/common/dwarf_global.c | 645 |
1 files changed, 394 insertions, 251 deletions
diff --git a/usr/src/tools/ctf/dwarf/common/dwarf_global.c b/usr/src/tools/ctf/dwarf/common/dwarf_global.c index 6ba561ef5b..d1c090fa43 100644 --- a/usr/src/tools/ctf/dwarf/common/dwarf_global.c +++ b/usr/src/tools/ctf/dwarf/common/dwarf_global.c @@ -1,6 +1,7 @@ /* - Copyright (C) 2000, 2002 Silicon Graphics, Inc. All Rights Reserved. + Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2.1 of the GNU Lesser General Public License @@ -19,10 +20,10 @@ You should have received a copy of the GNU Lesser General Public License along with this program; if not, write the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, USA. - Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky, + Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, Mountain View, CA 94043, or: http://www.sgi.com @@ -32,6 +33,12 @@ http://oss.sgi.com/projects/GenInfo/NoticeExplan */ +/* The address of the Free Software Foundation is + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. + SGI has moved from the Crittenden Lane address. +*/ + @@ -40,35 +47,106 @@ #include <stdio.h> #include "dwarf_global.h" + +#ifdef __sgi /* __sgi should only be defined for IRIX/MIPS. */ +/* The 'fixup' here intended for IRIX targets only. + With a 2+GB Elf64 IRIX executable (under 4GB in size), + some DIE offsets wrongly + got the 32bit upper bit sign extended. For the cu-header + offset in the .debug_pubnames section and in the + .debug_aranges section. + the 'varp' here is a pointer to an offset into .debug_info. + We fix up the offset here if it seems advisable.. + + As of June 2005 we have identified a series of mistakes + in ldx64 that can cause this (64 bit values getting passed + thru 32-bit signed knothole). +*/ +void +_dwarf_fix_up_offset_irix(Dwarf_Debug dbg, + Dwarf_Unsigned * varp, char *caller_site_name) +{ + + Dwarf_Unsigned var = *varp; + +#define UPPER33 0xffffffff80000000LL +#define LOWER32 0xffffffffLL + /* Restrict the hack to the known case. Upper 32 bits erroneously + sign extended from lower 32 upper bit. */ + if ((var & UPPER33) == UPPER33) { + var &= LOWER32; + /* Apply the fix. Dreadful hack. */ + *varp = var; + } +#undef UPPER33 +#undef LOWER32 + return; +} +#endif + + int dwarf_get_globals(Dwarf_Debug dbg, - Dwarf_Global ** globals, - Dwarf_Signed * return_count, Dwarf_Error * error) + Dwarf_Global ** globals, + Dwarf_Signed * return_count, Dwarf_Error * error) { - int res; - - res = - _dwarf_load_section(dbg, - dbg->de_debug_pubnames_index, - &dbg->de_debug_pubnames, - error); + int res = _dwarf_load_section(dbg, &dbg->de_debug_pubnames,error); if (res != DW_DLV_OK) { return res; } + return _dwarf_internal_get_pubnames_like_data(dbg, + dbg->de_debug_pubnames.dss_data, + dbg->de_debug_pubnames.dss_size, + globals, + return_count, + error, + DW_DLA_GLOBAL_CONTEXT, + DW_DLA_GLOBAL, + DW_DLE_PUBNAMES_LENGTH_BAD, + DW_DLE_PUBNAMES_VERSION_ERROR); +} - return _dwarf_internal_get_pubnames_like_data(dbg, - dbg-> - de_debug_pubnames, - dbg-> - de_debug_pubnames_size, - globals, return_count, - error, - DW_DLA_GLOBAL_CONTEXT, - DW_DLE_PUBNAMES_LENGTH_BAD, - DW_DLE_PUBNAMES_VERSION_ERROR); +/* Deallocating fully requires deallocating the list + and all entries. But some internal data is + not exposed, so we need a function with internal knowledge. +*/ + +void +dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl, + Dwarf_Signed count) +{ + _dwarf_internal_globals_dealloc(dbg, dwgl, + count, + DW_DLA_GLOBAL_CONTEXT, + DW_DLA_GLOBAL, DW_DLA_LIST); + return; +} + +void +_dwarf_internal_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl, + Dwarf_Signed count, + int context_code, + int global_code, int list_code) +{ + Dwarf_Signed i; + struct Dwarf_Global_Context_s *gcp = 0; + struct Dwarf_Global_Context_s *lastgcp = 0; + + for (i = 0; i < count; i++) { + Dwarf_Global dgb = dwgl[i]; + gcp = dgb->gl_context; + + if (lastgcp != gcp) { + lastgcp = gcp; + dwarf_dealloc(dbg, gcp, context_code); + } + dwarf_dealloc(dbg, dgb, global_code); + } + dwarf_dealloc(dbg, dwgl, list_code); + return; } @@ -76,212 +154,221 @@ dwarf_get_globals(Dwarf_Debug dbg, */ int _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, - Dwarf_Small * section_data_ptr, - Dwarf_Unsigned section_length, - Dwarf_Global ** globals, - Dwarf_Signed * return_count, - Dwarf_Error * error, - int allocation_code, - int length_err_num, - int version_err_num) + Dwarf_Small * section_data_ptr, + Dwarf_Unsigned section_length, + Dwarf_Global ** globals, + Dwarf_Signed * return_count, + Dwarf_Error * error, + int context_code, + int global_code, + int length_err_num, + int version_err_num) { - Dwarf_Small *pubnames_like_ptr; + Dwarf_Small *pubnames_like_ptr = 0; - /* - Points to the context for the current set of global names, and + /* Points to the context for the current set of global names, and contains information to identify the compilation-unit that the set refers to. */ - Dwarf_Global_Context pubnames_context; + Dwarf_Global_Context pubnames_context = 0; - Dwarf_Half version; + Dwarf_Half version = 0; /* Offset from the start of compilation-unit for the current global. */ - Dwarf_Off die_offset_in_cu; + Dwarf_Off die_offset_in_cu = 0; Dwarf_Unsigned global_count = 0; /* Points to the current global read. */ - Dwarf_Global global; + Dwarf_Global global = 0; - /* - Used to chain the Dwarf_Global_s structs for creating contiguous + /* Used to chain the Dwarf_Global_s structs for creating contiguous list of pointers to the structs. */ - Dwarf_Chain curr_chain, prev_chain, head_chain = NULL; + Dwarf_Chain curr_chain = 0; + Dwarf_Chain prev_chain = 0; + Dwarf_Chain head_chain = 0; /* Points to contiguous block of Dwarf_Global's to be returned. */ - Dwarf_Global *ret_globals; + Dwarf_Global *ret_globals = 0; /* Temporary counter. */ - Dwarf_Unsigned i; + Dwarf_Unsigned i = 0; if (dbg == NULL) { - _dwarf_error(NULL, error, DW_DLE_DBG_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); } /* We will eventually need the .debug_info data. Load it now. */ - if(!dbg->de_debug_info) { - int res = _dwarf_load_debug_info(dbg,error); - if(res != DW_DLV_OK) { - return res; + if (!dbg->de_debug_info.dss_data) { + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; } } if (section_data_ptr == NULL) { - return (DW_DLV_NO_ENTRY); + return (DW_DLV_NO_ENTRY); } pubnames_like_ptr = section_data_ptr; do { - Dwarf_Unsigned length; - int local_extension_size; - int local_length_size; - - /* Some compilers emit padding at the end of each cu's - area. pubnames_ptr_past_end_cu records the true - area end for this cu's data. Essentially the - length in the header and the 0 terminator of the - data are redundant information. The dwarf2/3 - spec does not mention what to do if the length - is past the 0 terminator. So we take any bytes - left after the 0 as padding and ignore them. */ + Dwarf_Unsigned length = 0; + int local_extension_size = 0; + int local_length_size = 0; + + /* Some compilers emit padding at the end of each cu's area. + pubnames_ptr_past_end_cu records the true area end for this + cu's data. Essentially the length in the header and the 0 + terminator of the data are redundant information. The + dwarf2/3 spec does not mention what to do if the length is + past the 0 terminator. So we take any bytes left after the 0 + as padding and ignore them. */ Dwarf_Small *pubnames_ptr_past_end_cu = 0; - - - pubnames_context = (Dwarf_Global_Context) - _dwarf_get_alloc(dbg, allocation_code, 1); - if (pubnames_context == NULL) { - _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); - return (DW_DLV_ERROR); - } - /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed - bytes */ - READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, - pubnames_like_ptr, local_length_size, - local_extension_size); - pubnames_context->pu_length_size = local_length_size; - pubnames_context->pu_extension_size = local_extension_size; - pubnames_context->pu_dbg = dbg; - - pubnames_ptr_past_end_cu = pubnames_like_ptr + length; - - READ_UNALIGNED(dbg, version, Dwarf_Half, - pubnames_like_ptr, sizeof(Dwarf_Half)); - pubnames_like_ptr += sizeof(Dwarf_Half); - if (version != CURRENT_VERSION_STAMP) { - _dwarf_error(dbg, error, version_err_num); - return (DW_DLV_ERROR); - } - - /* offset of CU header in debug section */ - READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header, - Dwarf_Off, pubnames_like_ptr, - pubnames_context->pu_length_size); - pubnames_like_ptr += pubnames_context->pu_length_size; - - - READ_UNALIGNED(dbg, pubnames_context->pu_info_length, - Dwarf_Unsigned, pubnames_like_ptr, - pubnames_context->pu_length_size); - pubnames_like_ptr += pubnames_context->pu_length_size; - - if (pubnames_like_ptr > (section_data_ptr + section_length)) { - _dwarf_error(dbg, error, length_err_num); - return (DW_DLV_ERROR); - } - - /* read initial offset (of DIE within CU) of a pubname, final - entry is not a pair, just a zero offset */ - READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, - pubnames_like_ptr, - pubnames_context->pu_length_size); - pubnames_like_ptr += pubnames_context->pu_length_size; - - /* loop thru pairs. DIE off with CU followed by string */ - while (die_offset_in_cu != 0) { - - /* Already read offset, pubnames_like_ptr now points to the - string */ - global = - (Dwarf_Global) _dwarf_get_alloc(dbg, DW_DLA_GLOBAL, 1); - if (global == NULL) { - _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); - return (DW_DLV_ERROR); - } - global_count++; - - global->gl_context = pubnames_context; - - global->gl_named_die_offset_within_cu = die_offset_in_cu; - - global->gl_name = pubnames_like_ptr; - - pubnames_like_ptr = pubnames_like_ptr + - strlen((char *) pubnames_like_ptr) + 1; - - - /* finish off current entry chain */ - curr_chain = - (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); - if (curr_chain == NULL) { - _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); - return (DW_DLV_ERROR); - } - - /* Put current global on singly_linked list. */ - curr_chain->ch_item = (Dwarf_Global) global; - - if (head_chain == NULL) - head_chain = prev_chain = curr_chain; - else { - prev_chain->ch_next = curr_chain; - prev_chain = curr_chain; - } - - /* read offset for the *next* entry */ - READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, - pubnames_like_ptr, - pubnames_context->pu_length_size); - - pubnames_like_ptr += pubnames_context->pu_length_size; - if (pubnames_like_ptr > (section_data_ptr + section_length)) { - _dwarf_error(dbg, error, length_err_num); - return (DW_DLV_ERROR); - } - } - /* ASSERT: die_offset_in_cu == 0 */ - if(pubnames_like_ptr > pubnames_ptr_past_end_cu) { - /* This is some kind of error. This simply cannot happen. - The encoding is wrong or the length in the header - for this cu's contribution is wrong. */ - _dwarf_error(dbg, error, length_err_num); - return (DW_DLV_ERROR); - + + + pubnames_context = (Dwarf_Global_Context) + _dwarf_get_alloc(dbg, context_code, 1); + if (pubnames_context == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed + bytes. */ + READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned, + pubnames_like_ptr, local_length_size, + local_extension_size); + pubnames_context->pu_length_size = local_length_size; + pubnames_context->pu_extension_size = local_extension_size; + pubnames_context->pu_dbg = dbg; + + pubnames_ptr_past_end_cu = pubnames_like_ptr + length; + + READ_UNALIGNED(dbg, version, Dwarf_Half, + pubnames_like_ptr, sizeof(Dwarf_Half)); + pubnames_like_ptr += sizeof(Dwarf_Half); + if (version != CURRENT_VERSION_STAMP) { + _dwarf_error(dbg, error, version_err_num); + return (DW_DLV_ERROR); + } + + /* Offset of CU header in debug section. */ + READ_UNALIGNED(dbg, pubnames_context->pu_offset_of_cu_header, + Dwarf_Off, pubnames_like_ptr, + pubnames_context->pu_length_size); + pubnames_like_ptr += pubnames_context->pu_length_size; + + FIX_UP_OFFSET_IRIX_BUG(dbg, + pubnames_context->pu_offset_of_cu_header, + "pubnames cu header offset"); + + + READ_UNALIGNED(dbg, pubnames_context->pu_info_length, + Dwarf_Unsigned, pubnames_like_ptr, + pubnames_context->pu_length_size); + pubnames_like_ptr += pubnames_context->pu_length_size; + + if (pubnames_like_ptr > (section_data_ptr + section_length)) { + _dwarf_error(dbg, error, length_err_num); + return (DW_DLV_ERROR); } - /* If there is some kind of padding at the end of - the section, as emitted by some compilers, - skip over that padding and simply ignore the bytes - thus passed-over. With most compilers, - pubnames_like_ptr == pubnames_ptr_past_end_cu - at this point */ - pubnames_like_ptr = pubnames_ptr_past_end_cu; + + /* Read initial offset (of DIE within CU) of a pubname, final + entry is not a pair, just a zero offset. */ + READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, + pubnames_like_ptr, + pubnames_context->pu_length_size); + pubnames_like_ptr += pubnames_context->pu_length_size; + FIX_UP_OFFSET_IRIX_BUG(dbg, + die_offset_in_cu, "offset of die in cu"); + + /* Loop thru pairs. DIE off with CU followed by string. */ + while (die_offset_in_cu != 0) { + + /* Already read offset, pubnames_like_ptr now points to the + string. */ + global = + (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1); + if (global == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + global_count++; + + global->gl_context = pubnames_context; + + global->gl_named_die_offset_within_cu = die_offset_in_cu; + + global->gl_name = pubnames_like_ptr; + + pubnames_like_ptr = pubnames_like_ptr + + strlen((char *) pubnames_like_ptr) + 1; + + + /* finish off current entry chain */ + curr_chain = + (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + /* Put current global on singly_linked list. */ + curr_chain->ch_item = (Dwarf_Global) global; + + if (head_chain == NULL) + head_chain = prev_chain = curr_chain; + else { + prev_chain->ch_next = curr_chain; + prev_chain = curr_chain; + } + + /* read offset for the *next* entry */ + READ_UNALIGNED(dbg, die_offset_in_cu, Dwarf_Off, + pubnames_like_ptr, + pubnames_context->pu_length_size); + + pubnames_like_ptr += pubnames_context->pu_length_size; + FIX_UP_OFFSET_IRIX_BUG(dbg, + die_offset_in_cu, + "offset of next die in cu"); + + if (pubnames_like_ptr > (section_data_ptr + section_length)) { + _dwarf_error(dbg, error, length_err_num); + return (DW_DLV_ERROR); + } + } + /* ASSERT: die_offset_in_cu == 0 */ + if (pubnames_like_ptr > pubnames_ptr_past_end_cu) { + /* This is some kind of error. This simply cannot happen. + The encoding is wrong or the length in the header for + this cu's contribution is wrong. */ + _dwarf_error(dbg, error, length_err_num); + return (DW_DLV_ERROR); + } + /* If there is some kind of padding at the end of the section, + as emitted by some compilers, skip over that padding and + simply ignore the bytes thus passed-over. With most + compilers, pubnames_like_ptr == pubnames_ptr_past_end_cu at + this point */ + pubnames_like_ptr = pubnames_ptr_past_end_cu; } while (pubnames_like_ptr < (section_data_ptr + section_length)); /* Points to contiguous block of Dwarf_Global's. */ ret_globals = (Dwarf_Global *) - _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count); + _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count); if (ret_globals == NULL) { - _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); - return (DW_DLV_ERROR); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); } /* @@ -289,29 +376,30 @@ _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, and deallocate the chain. */ curr_chain = head_chain; for (i = 0; i < global_count; i++) { - *(ret_globals + i) = curr_chain->ch_item; - prev_chain = curr_chain; - curr_chain = curr_chain->ch_next; - dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); + *(ret_globals + i) = curr_chain->ch_item; + prev_chain = curr_chain; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } *globals = ret_globals; - *return_count = (global_count); + *return_count = (Dwarf_Signed) global_count; return DW_DLV_OK; } + /* - Given a pubnames entry (or other like section entry) - return thru the ret_name pointer - a pointer to the string which is the entry name. - + Given a pubnames entry (or other like section entry) + return thru the ret_name pointer + a pointer to the string which is the entry name. + */ int dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error) { if (glob == NULL) { - _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); } *ret_name = (char *) (glob->gl_name); @@ -320,40 +408,40 @@ dwarf_globname(Dwarf_Global glob, char **ret_name, Dwarf_Error * error) /* - Given a pubnames entry (or other like section entry) - return thru the ret_off pointer the - global offset of the DIE for this entry. - The global offset is the offset within the .debug_info - section as a whole. + Given a pubnames entry (or other like section entry) + return thru the ret_off pointer the + global offset of the DIE for this entry. + The global offset is the offset within the .debug_info + section as a whole. */ int dwarf_global_die_offset(Dwarf_Global global, - Dwarf_Off * ret_off, Dwarf_Error * error) + Dwarf_Off * ret_off, Dwarf_Error * error) { if (global == NULL) { - _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); } if (global->gl_context == NULL) { - _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return (DW_DLV_ERROR); } *ret_off = (global->gl_named_die_offset_within_cu + - global->gl_context->pu_offset_of_cu_header); + global->gl_context->pu_offset_of_cu_header); return DW_DLV_OK; } /* - Given a pubnames entry (or other like section entry) - return thru the ret_off pointer the - offset of the compilation unit header of the + Given a pubnames entry (or other like section entry) + return thru the ret_off pointer the + offset of the compilation unit header of the compilation unit the global is part of. - In early versions of this, the value returned was + In early versions of this, the value returned was the offset of the compilation unit die, and - other cu-local die offsets were faked so adding this to + other cu-local die offsets were faked so adding this to such a cu-local offset got a true section offset. Now things do as they say (adding *cu_header_offset to a cu-local offset gets the section offset). @@ -361,21 +449,21 @@ dwarf_global_die_offset(Dwarf_Global global, */ int dwarf_global_cu_offset(Dwarf_Global global, - Dwarf_Off * cu_header_offset, - Dwarf_Error * error) + Dwarf_Off * cu_header_offset, + Dwarf_Error * error) { - Dwarf_Global_Context con; + Dwarf_Global_Context con = 0; if (global == NULL) { - _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); } con = global->gl_context; if (con == NULL) { - _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return (DW_DLV_ERROR); } /* In early libdwarf, this incorrectly returned the offset of the @@ -388,77 +476,132 @@ dwarf_global_cu_offset(Dwarf_Global global, /* Give back the pubnames entry (or any other like section) name, symbol DIE offset, and the cu-DIE offset. + + Various errors are possible. + + The string pointer returned thru ret_name is not + dwarf_get_alloc()ed, so no dwarf_dealloc() + DW_DLA_STRING should be applied to it. + */ int dwarf_global_name_offsets(Dwarf_Global global, - char **ret_name, - Dwarf_Off * die_offset, - Dwarf_Off * cu_die_offset, - Dwarf_Error * error) + char **ret_name, + Dwarf_Off * die_offset, + Dwarf_Off * cu_die_offset, + Dwarf_Error * error) { - Dwarf_Global_Context con; - Dwarf_Debug dbg; - Dwarf_Off off; + Dwarf_Global_Context con = 0; + Dwarf_Debug dbg = 0; + Dwarf_Off off = 0; if (global == NULL) { - _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); + return (DW_DLV_ERROR); } con = global->gl_context; if (con == NULL) { - _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_GLOBAL_CONTEXT_NULL); + return (DW_DLV_ERROR); } off = con->pu_offset_of_cu_header; - if (die_offset != NULL) { - *die_offset = global->gl_named_die_offset_within_cu + off; - } - + /* The offset had better not be too close to the end. If it is, + _dwarf_length_of_cu_header() will step off the end and therefore + must not be used. 10 is a meaningless heuristic, but no CU + header is that small so it is safe. An erroneous offset is due + to a bug in the tool chain. A bug like this has been seen on + IRIX with MIPSpro 7.3.1.3 and an executable > 2GB in size and + with 2 million pubnames entries. */ +#define MIN_CU_HDR_SIZE 10 dbg = con->pu_dbg; if (dbg == NULL) { - _dwarf_error(NULL, error, DW_DLE_DBG_NULL); - return (DW_DLV_ERROR); + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return (DW_DLV_ERROR); + } + if (dbg->de_debug_info.dss_size && + ((off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) { + _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD); + return (DW_DLV_ERROR); } +#undef MIN_CU_HDR_SIZE + if (die_offset != NULL) { + *die_offset = global->gl_named_die_offset_within_cu + off; + } + + *ret_name = (char *) global->gl_name; if (cu_die_offset != NULL) { - int res = _dwarf_load_debug_info(dbg,error); - if(res != DW_DLV_OK) { - return res; - } - *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off); + int res = _dwarf_load_debug_info(dbg, error); + + if (res != DW_DLV_OK) { + return res; + } + /* The offset had better not be too close to the end. If it is, + _dwarf_length_of_cu_header() will step off the end and + therefore must not be used. 10 is a meaningless heuristic, + but no CU header is that small so it is safe. */ + if ((off + 10) >= dbg->de_debug_info.dss_size) { + _dwarf_error(NULL, error, DW_DLE_OFFSET_BAD); + return (DW_DLV_ERROR); + } + *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off); } - *ret_name = (char *) global->gl_name; return DW_DLV_OK; } /* - We have the offset to a CU header. - Return thru outFileOffset the offset of the CU DIE. - - New June, 2001. - Used by SGI debuggers. - No error is possible. + We have the offset to a CU header. + Return thru outFileOffset the offset of the CU DIE. + + New June, 2001. + Used by SGI debuggers. + No error is possible. + + See also dwarf_CU_dieoffset_given_die(). */ /* ARGSUSED */ int dwarf_get_cu_die_offset_given_cu_header_offset(Dwarf_Debug dbg, - Dwarf_Off - in_cu_header_offset, - Dwarf_Off * - out_cu_die_offset, - Dwarf_Error * err) + Dwarf_Off in_cu_header_offset, + Dwarf_Off * out_cu_die_offset, + Dwarf_Error * err) { Dwarf_Off len = - _dwarf_length_of_cu_header(dbg, in_cu_header_offset); + _dwarf_length_of_cu_header(dbg, in_cu_header_offset); Dwarf_Off newoff = in_cu_header_offset + len; *out_cu_die_offset = newoff; return DW_DLV_OK; } +/* dwarf_CU_dieoffset_given_die returns + the global debug_info section offset of the CU die + that is the CU containing the given (passed-in) die. + This information makes it possible for a consumer to + find and print context information for any die. + + Use dwarf_offdie() passing in the offset this returns + to get a die pointer to the CU die. + */ +int +dwarf_CU_dieoffset_given_die(Dwarf_Die die, + Dwarf_Off* return_offset, + Dwarf_Error* error) +{ + Dwarf_Off dieoff = 0; + Dwarf_CU_Context cucontext = 0; + + CHECK_DIE(die, DW_DLV_ERROR); + cucontext = die->di_cu_context; + dieoff = cucontext->cc_debug_info_offset; + /* The following call cannot fail, so no error check. */ + dwarf_get_cu_die_offset_given_cu_header_offset( + cucontext->cc_dbg, dieoff, return_offset,error); + return DW_DLV_OK; +} |
