diff options
Diffstat (limited to 'usr/src/lib/libdwarf/common/dwarf_global.c')
-rw-r--r-- | usr/src/lib/libdwarf/common/dwarf_global.c | 766 |
1 files changed, 524 insertions, 242 deletions
diff --git a/usr/src/lib/libdwarf/common/dwarf_global.c b/usr/src/lib/libdwarf/common/dwarf_global.c index d1c090fa43..63d57a2f40 100644 --- a/usr/src/lib/libdwarf/common/dwarf_global.c +++ b/usr/src/lib/libdwarf/common/dwarf_global.c @@ -1,66 +1,56 @@ /* Copyright (C) 2000-2005 Silicon Graphics, Inc. All Rights Reserved. - Portions Copyright (C) 2007-2010 David Anderson. All Rights Reserved. + Portions Copyright (C) 2007-2011 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 as published by the Free + Software Foundation. + + This program is distributed in the hope that it would be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. + + Further, this software is distributed without any warranty + that it is free of the rightful claim of any third person + regarding infringement or the like. Any license provided + herein, whether implied or otherwise, applies only to this + software file. Patent licenses, if any, provided herein + do not apply to combinations of this program with other + software, or any other product whatsoever. + + 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., 51 Franklin Street - Fifth + Floor, Boston MA 02110-1301, USA. - 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 - as published by the Free Software Foundation. - - This program is distributed in the hope that it would be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - Further, this software is distributed without any warranty that it is - free of the rightful claim of any third person regarding infringement - or the like. Any license provided herein, whether implied or - otherwise, applies only to this software file. Patent licenses, if - any, provided herein do not apply to combinations of this program with - other software, or any other product whatsoever. - - 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., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, - USA. - - Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, - Mountain View, CA 94043, or: - - http://www.sgi.com - - For further information regarding this notice, see: - - 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. */ - - - #include "config.h" -#include "dwarf_incl.h" #include <stdio.h> +#include "dwarf_incl.h" +#include "dwarf_alloc.h" +#include "dwarf_error.h" +#include "dwarf_util.h" +#include "dwarfstring.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), + 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). + thru 32-bit signed knothole). */ void _dwarf_fix_up_offset_irix(Dwarf_Debug dbg, @@ -71,8 +61,8 @@ _dwarf_fix_up_offset_irix(Dwarf_Debug dbg, #define UPPER33 0xffffffff80000000LL #define LOWER32 0xffffffffLL - /* Restrict the hack to the known case. Upper 32 bits erroneously - sign extended from lower 32 upper bit. */ + /* 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. */ @@ -82,8 +72,28 @@ _dwarf_fix_up_offset_irix(Dwarf_Debug dbg, #undef LOWER32 return; } -#endif +#endif /* __sgi */ + +static void +dealloc_globals_chain(Dwarf_Debug dbg, + Dwarf_Chain head_chain) +{ + Dwarf_Chain curr_chain = 0; + Dwarf_Chain prev_chain = 0; + int chaintype = DW_DLA_CHAIN; + curr_chain = head_chain; + for (; curr_chain; ) { + void *item = curr_chain->ch_item; + int itemtype = curr_chain->ch_itemtype; + + prev_chain = curr_chain; + dwarf_dealloc(dbg, item,itemtype); + prev_chain->ch_item = 0; + curr_chain = curr_chain->ch_next; + dwarf_dealloc(dbg, prev_chain, chaintype); + } +} int dwarf_get_globals(Dwarf_Debug dbg, @@ -94,17 +104,21 @@ dwarf_get_globals(Dwarf_Debug dbg, if (res != DW_DLV_OK) { return res; } + if (!dbg->de_debug_pubnames.dss_size) { + return DW_DLV_NO_ENTRY; + } - return _dwarf_internal_get_pubnames_like_data(dbg, + res = _dwarf_internal_get_pubnames_like_data(dbg, dbg->de_debug_pubnames.dss_data, dbg->de_debug_pubnames.dss_size, - globals, + globals, return_count, error, DW_DLA_GLOBAL_CONTEXT, DW_DLA_GLOBAL, DW_DLE_PUBNAMES_LENGTH_BAD, DW_DLE_PUBNAMES_VERSION_ERROR); + return res; } @@ -127,31 +141,38 @@ dwarf_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl, void _dwarf_internal_globals_dealloc(Dwarf_Debug dbg, Dwarf_Global * dwgl, Dwarf_Signed count, - int context_code, - int global_code, int list_code) + int context_DLA_code, + int global_DLA_code, int list_DLA_code) { Dwarf_Signed i; - struct Dwarf_Global_Context_s *gcp = 0; - struct Dwarf_Global_Context_s *lastgcp = 0; + struct Dwarf_Global_Context_s *glcp = 0; + struct Dwarf_Global_Context_s *lastglcp = 0; + if(!dwgl) { + return; + } 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); + if (!dgb) { + continue; + } + /* Avoids duplicate frees of repeated + use of contexts (while assuming that + all uses of a particular gl_context + will appear next to each other. */ + glcp = dgb->gl_context; + if (lastglcp != glcp) { + lastglcp = glcp; + dwarf_dealloc(dbg, glcp, context_DLA_code); } - dwarf_dealloc(dbg, dgb, global_code); + dwarf_dealloc(dbg, dgb, global_DLA_code); } - dwarf_dealloc(dbg, dwgl, list_code); + dwarf_dealloc(dbg, dwgl, list_DLA_code); return; } - -/* Sweeps the complete section. -*/ +/* Sweeps the complete section. */ int _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, Dwarf_Small * section_data_ptr, @@ -159,27 +180,24 @@ _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, Dwarf_Global ** globals, Dwarf_Signed * return_count, Dwarf_Error * error, - int context_code, - int global_code, + int context_DLA_code, + int global_DLA_code, int length_err_num, int version_err_num) { - - Dwarf_Small *pubnames_like_ptr = 0; + Dwarf_Off pubnames_section_offset = 0; + Dwarf_Small *section_end_ptr = section_data_ptr +section_length; - - - /* Points to the context for the current set of global names, and - contains information to identify the compilation-unit that the - set refers to. */ + /* 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 = 0; - Dwarf_Half version = 0; + Dwarf_Unsigned version = 0; - /* - Offset from the start of compilation-unit for the current - global. */ + /* Offset from the start of compilation-unit for the current + global. */ Dwarf_Off die_offset_in_cu = 0; Dwarf_Unsigned global_count = 0; @@ -187,21 +205,19 @@ _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, /* Points to the current global read. */ Dwarf_Global global = 0; - /* Used to chain the Dwarf_Global_s structs for creating contiguous - list of pointers to the structs. */ + /* Used to chain the Dwarf_Global_s structs for creating contiguous + list of pointers to the structs. */ 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 = 0; + int mres = 0; /* Temporary counter. */ Dwarf_Unsigned i = 0; - - - if (dbg == NULL) { _dwarf_error(NULL, error, DW_DLE_DBG_NULL); return (DW_DLV_ERROR); @@ -214,116 +230,217 @@ _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, return res; } } - if (section_data_ptr == NULL) { return (DW_DLV_NO_ENTRY); } - pubnames_like_ptr = section_data_ptr; do { 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. */ + /* Some compilers emit padding at the end of each cu's area. + pubnames_ptr_past_end_cu records the true area end for the + pubnames(like) content of a cu. + 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, context_code, 1); + _dwarf_get_alloc(dbg, context_DLA_code, 1); if (pubnames_context == NULL) { + dealloc_globals_chain(dbg,head_chain); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); - return (DW_DLV_ERROR); + return DW_DLV_ERROR; + } + /* READ_AREA_LENGTH updates pubnames_like_ptr for consumed + bytes. */ + mres = _dwarf_read_area_length_ck_wrapper(dbg, + &length,&pubnames_like_ptr,&local_length_size, + &local_extension_size,section_length,section_end_ptr, + error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + return mres; } - /* 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_length = length; pubnames_context->pu_extension_size = local_extension_size; pubnames_context->pu_dbg = dbg; - + pubnames_context->pu_pub_offset = pubnames_section_offset; 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) { + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &version,pubnames_like_ptr,DWARF_HALF_SIZE, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + return mres; + } + pubnames_context->pu_version = version; + pubnames_like_ptr += DWARF_HALF_SIZE; + /* ASSERT: DW_PUBNAMES_VERSION2 == DW_PUBTYPES_VERSION2 */ + if (version != DW_PUBNAMES_VERSION2) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); _dwarf_error(dbg, error, version_err_num); - return (DW_DLV_ERROR); + 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); + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &pubnames_context->pu_offset_of_cu_header, + pubnames_like_ptr, + pubnames_context->pu_length_size, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + return mres; + } + 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_context->pu_offset_of_cu_header, + "pubnames cu header offset"); + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &pubnames_context->pu_info_length, + pubnames_like_ptr, + pubnames_context->pu_length_size, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + return mres; + } pubnames_like_ptr += pubnames_context->pu_length_size; if (pubnames_like_ptr > (section_data_ptr + section_length)) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); _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); + /* Read initial offset (of DIE within CU) of a pubname, final + entry is not a pair, just a zero offset. */ + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &die_offset_in_cu, + pubnames_like_ptr, + pubnames_context->pu_length_size, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + return mres; + } pubnames_like_ptr += pubnames_context->pu_length_size; FIX_UP_OFFSET_IRIX_BUG(dbg, - die_offset_in_cu, "offset of die in cu"); + die_offset_in_cu, "offset of die in cu"); + if (pubnames_like_ptr > (section_data_ptr + section_length)) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + _dwarf_error(dbg, error, length_err_num); + return DW_DLV_ERROR; + } /* 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. */ + if (dbg->de_return_empty_pubnames && die_offset_in_cu == 0) { + /* Here we have a pubnames CU with no actual + entries so we fake up an entry to hold the + header data. There are no 'pairs' here, + just the end of list zero value. We do this + only if de_return_empty_pubnames is set + so that we by default return exactly the same + data this always returned, yet dwarfdump can + request the empty-cu records get created + to test that feature. + see dwarf_get_globals_header() */ global = - (Dwarf_Global) _dwarf_get_alloc(dbg, global_code, 1); + (Dwarf_Global) _dwarf_get_alloc(dbg, global_DLA_code, 1); if (global == NULL) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); _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 = 0; + global->gl_name = (Dwarf_Small *)""; + /* Finish off current entry chain */ + curr_chain = + (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); + if (curr_chain == NULL) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return DW_DLV_ERROR; + } + /* Put current global on singly_linked list. */ + curr_chain->ch_itemtype = global_DLA_code; + 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; + } + /* There is no next entry, we are at it already */ + } else if (!die_offset_in_cu) { + /* The section is empty. + Nowhere to record pubnames_context); */ + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + pubnames_context = 0; + continue; + } + while (die_offset_in_cu) { + int res = 0; + /* Already read offset, pubnames_like_ptr + now points to the string. */ + global = + (Dwarf_Global) _dwarf_get_alloc(dbg, global_DLA_code, 1); + if (global == NULL) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + _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; - + res = _dwarf_check_string_valid(dbg,section_data_ptr, + pubnames_like_ptr,section_end_ptr, + DW_DLE_STRING_OFF_END_PUBNAMES_LIKE,error); + if (res != DW_DLV_OK) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + return res; + } pubnames_like_ptr = pubnames_like_ptr + strlen((char *) pubnames_like_ptr) + 1; - - /* finish off current entry chain */ + /* Finish off current entry chain */ curr_chain = (Dwarf_Chain) _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1); if (curr_chain == NULL) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); _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; - + curr_chain->ch_itemtype = global_DLA_code; if (head_chain == NULL) head_chain = prev_chain = curr_chain; else { @@ -331,19 +448,25 @@ _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, 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); - + /* Read offset for the *next* entry */ + mres = _dwarf_read_unaligned_ck_wrapper(dbg, + &die_offset_in_cu, + pubnames_like_ptr, + pubnames_context->pu_length_size, + section_end_ptr,error); + if (mres != DW_DLV_OK) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + return mres; + } pubnames_like_ptr += pubnames_context->pu_length_size; FIX_UP_OFFSET_IRIX_BUG(dbg, - die_offset_in_cu, - "offset of next die in cu"); - + die_offset_in_cu, "offset of next die in cu"); if (pubnames_like_ptr > (section_data_ptr + section_length)) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); _dwarf_error(dbg, error, length_err_num); - return (DW_DLV_ERROR); + return DW_DLV_ERROR; } } /* ASSERT: die_offset_in_cu == 0 */ @@ -352,48 +475,55 @@ _dwarf_internal_get_pubnames_like_data(Dwarf_Debug dbg, 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); + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); + 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 */ + { + Dwarf_Unsigned increment = + pubnames_context->pu_length_size + + pubnames_context->pu_length + + pubnames_context->pu_extension_size; + pubnames_section_offset += increment; } - /* 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)); + } while (pubnames_like_ptr < section_end_ptr); /* Points to contiguous block of Dwarf_Global's. */ ret_globals = (Dwarf_Global *) _dwarf_get_alloc(dbg, DW_DLA_LIST, global_count); if (ret_globals == NULL) { + dealloc_globals_chain(dbg,head_chain); + dwarf_dealloc(dbg,pubnames_context,context_DLA_code); _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); - return (DW_DLV_ERROR); + return DW_DLV_ERROR; } - /* - Store pointers to Dwarf_Global_s structs in contiguous block, - and deallocate the chain. */ + /* Store pointers to Dwarf_Global_s structs in contiguous block, + and deallocate the chain. This ignores the various + headers */ 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; + prev_chain->ch_item = 0; /* Not actually necessary. */ dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN); } - *globals = ret_globals; *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) { @@ -407,16 +537,14 @@ 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); @@ -429,28 +557,25 @@ dwarf_global_die_offset(Dwarf_Global global, } *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 - compilation unit the global is part of. - - 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 - 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). - -*/ +/* 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 + the offset of the compilation unit die, and + 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). */ 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 = 0; @@ -466,13 +591,34 @@ dwarf_global_cu_offset(Dwarf_Global global, return (DW_DLV_ERROR); } - /* In early libdwarf, this incorrectly returned the offset of the - CU DIE. Now correctly returns the header offset. */ + /* In early libdwarf, this incorrectly returned the offset of the + CU DIE. Now correctly returns the header offset. */ *cu_header_offset = con->pu_offset_of_cu_header; return DW_DLV_OK; } +static void +build_off_end_msg(Dwarf_Unsigned offval, + Dwarf_Unsigned withincr, + Dwarf_Unsigned secsize, + dwarfstring *m) +{ + const char *msg = "past"; + if (offval < secsize){ + msg = "too near"; + } + dwarfstring_append_printf_u(m,"DW_DLE_OFFSET_BAD: " + "The CU header offset of %u in a pubnames-like entry ", + withincr); + dwarfstring_append_printf_s(m, + "would put us %s the end of .debug_info. " + "No room for a DIE there... " + "Corrupt Dwarf.",(char *)msg); + return; +} + + /* Give back the pubnames entry (or any other like section) name, symbol DIE offset, and the cu-DIE offset. @@ -480,20 +626,20 @@ dwarf_global_cu_offset(Dwarf_Global global, Various errors are possible. The string pointer returned thru ret_name is not - dwarf_get_alloc()ed, so no dwarf_dealloc() + 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 = 0; Dwarf_Debug dbg = 0; - Dwarf_Off off = 0; + Dwarf_Off cuhdr_off = 0; if (global == NULL) { _dwarf_error(NULL, error, DW_DLE_GLOBAL_NULL); @@ -507,62 +653,152 @@ dwarf_global_name_offsets(Dwarf_Global global, return (DW_DLV_ERROR); } - off = con->pu_offset_of_cu_header; - /* 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. */ + cuhdr_off = con->pu_offset_of_cu_header; + /* 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); } + /* Cannot refer to debug_types */ 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); + ((cuhdr_off + MIN_CU_HDR_SIZE) >= dbg->de_debug_info.dss_size)) { + dwarfstring m; + dwarfstring_constructor(&m); + build_off_end_msg(cuhdr_off,cuhdr_off+MIN_CU_HDR_SIZE, + dbg->de_debug_info.dss_size,&m); + _dwarf_error_string(dbg, error, DW_DLE_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); return (DW_DLV_ERROR); } #undef MIN_CU_HDR_SIZE - if (die_offset != NULL) { - *die_offset = global->gl_named_die_offset_within_cu + off; + /* If global->gl_named_die_offset_within_cu + is zero then this is a fake global for + a pubnames CU with no pubnames. The offset is from the + start of the CU header, so no die can have a zero + offset, all valid offsets are positive numbers */ + if (die_offset) { + if(global->gl_named_die_offset_within_cu) { + *die_offset = global->gl_named_die_offset_within_cu + cuhdr_off; + } else { + *die_offset = 0; + } } - *ret_name = (char *) global->gl_name; - - if (cu_die_offset != NULL) { + if (cu_die_offset) { + /* Globals cannot refer to debug_types */ + int cres = 0; + Dwarf_Unsigned headerlen = 0; 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); + /* 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. */ + /* Globals cannot refer to debug_types */ + if ((cuhdr_off + 10) >= dbg->de_debug_info.dss_size) { + dwarfstring m; + + dwarfstring_constructor(&m); + build_off_end_msg(cuhdr_off,cuhdr_off+10, + dbg->de_debug_info.dss_size,&m); + _dwarf_error_string(dbg, error, DW_DLE_OFFSET_BAD, + dwarfstring_string(&m)); + dwarfstring_destructor(&m); return (DW_DLV_ERROR); } - *cu_die_offset = off + _dwarf_length_of_cu_header(dbg, off); + cres = _dwarf_length_of_cu_header(dbg, cuhdr_off,true, + &headerlen,error); + if(cres != DW_DLV_OK) { + return cres; + } + *cu_die_offset = cuhdr_off + headerlen; } + return DW_DLV_OK; +} +/* New February 2019 from better dwarfdump printing + of debug_pubnames and pubtypes. + For ao the Dwarf_Global records in one pubnames + CU group exactly the same data will be returned. + +*/ +int +dwarf_get_globals_header(Dwarf_Global global, + Dwarf_Off *pub_section_hdr_offset, + Dwarf_Unsigned *pub_offset_size, + Dwarf_Unsigned *pub_cu_length, + Dwarf_Unsigned *version, + Dwarf_Off *info_header_offset, + Dwarf_Unsigned *info_length, + Dwarf_Error* error) +{ + Dwarf_Global_Context con = 0; + Dwarf_Debug dbg = 0; + + if (global == NULL) { + _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; + } + dbg = con->pu_dbg; + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return DW_DLV_ERROR; + } + if(pub_section_hdr_offset) { + *pub_section_hdr_offset = con->pu_pub_offset; + } + if (pub_offset_size) { + *pub_offset_size = con->pu_length_size; + } + if (pub_cu_length) { + *pub_cu_length = con->pu_length; + } + if (version) { + *version = con->pu_version; + } + if(info_header_offset) { + *info_header_offset = con->pu_offset_of_cu_header; + } + if (info_length) { + *info_length = con->pu_info_length; + } 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. - - See also dwarf_CU_dieoffset_given_die(). + +/* We have the offset to a CU header. + Return thru outFileOffset the offset of the CU DIE. + + New June, 2001. + Used by SGI IRIX debuggers. + No error used to be possible. + As of May 2016 an error is possible if the DWARF is + corrupted! (IRIX debuggers are no longer built ...) + + See also dwarf_CU_dieoffset_given_die(). + + This is assumed to never apply to data in .debug_types, it + only refers to .debug_info. + */ /* ARGSUSED */ @@ -570,38 +806,84 @@ 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) + UNUSEDARG Dwarf_Error * err) { - Dwarf_Off len = - _dwarf_length_of_cu_header(dbg, in_cu_header_offset); + Dwarf_Off headerlen = 0; + int cres = 0; - Dwarf_Off newoff = in_cu_header_offset + len; + cres = _dwarf_length_of_cu_header(dbg, in_cu_header_offset,true, + &headerlen,err); + if (cres != DW_DLV_OK) { + return cres; + } + *out_cu_die_offset = in_cu_header_offset + headerlen; + return DW_DLV_OK; +} + +/* The following version new in October 2011, does allow finding + the offset if one knows whether debug_info or debug_types. + + However, it is not accurate in DWARF5 because + there are two different header lengths (CU and TU) + in DWARF5 .debug_info. In that case, pretend + that it's .debug_types (here) and pass is_info zero for + a TU (as if it was in .debug_types). + */ +int +dwarf_get_cu_die_offset_given_cu_header_offset_b(Dwarf_Debug dbg, + Dwarf_Off in_cu_header_offset, + Dwarf_Bool is_info, + Dwarf_Off * out_cu_die_offset, + UNUSEDARG Dwarf_Error * err) +{ + Dwarf_Off headerlen = 0; + int cres = 0; - *out_cu_die_offset = newoff; + cres = _dwarf_length_of_cu_header(dbg, in_cu_header_offset,is_info, + &headerlen,err); + if (cres != DW_DLV_OK) { + return cres; + } + *out_cu_die_offset = in_cu_header_offset + headerlen; 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 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); + dieoff = cucontext->cc_debug_offset; + /* The following call cannot fail, so no error check. */ + dwarf_get_cu_die_offset_given_cu_header_offset_b( + cucontext->cc_dbg, dieoff, + die->di_is_info, return_offset,error); + return DW_DLV_OK; +} + +/* We do not want to screw up error in case + it has something important. So not touching it now. */ +int dwarf_return_empty_pubnames(Dwarf_Debug dbg, + int flag, UNUSEDARG Dwarf_Error *err ) +{ + if (dbg == NULL) { + return DW_DLV_OK; + } + if (flag && flag != 1) { + return DW_DLV_OK; + } + dbg->de_return_empty_pubnames = (unsigned char)flag; return DW_DLV_OK; } |