diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-10-20 14:42:03 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-10-20 14:42:03 +0400 |
commit | bb1c3da3c12651f1c408d96dd6d33ae157bdadd6 (patch) | |
tree | 4a535b35500684ac6a928bf0fd661325b5a04697 /libdwarf/dwarf_form.c | |
download | dwarfutils-upstream/20120410.tar.gz |
Imported Upstream version 20120410upstream/20120410upstream
Diffstat (limited to 'libdwarf/dwarf_form.c')
-rw-r--r-- | libdwarf/dwarf_form.c | 931 |
1 files changed, 931 insertions, 0 deletions
diff --git a/libdwarf/dwarf_form.c b/libdwarf/dwarf_form.c new file mode 100644 index 0000000..c09b610 --- /dev/null +++ b/libdwarf/dwarf_form.c @@ -0,0 +1,931 @@ +/* + + Copyright (C) 2000,2002,2004,2005 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved. + Portions Copyright 2008-2011 David Anderson. All rights reserved. + Portions Copyright 2010 SN Systems Ltd. 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. + + 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 + +*/ + + + +#include "config.h" +#include "dwarf_incl.h" +#include "dwarf_die_deliv.h" + +/* This code was repeated many times, now it + is all in one place. */ +static int +get_attr_dbg(Dwarf_Debug *dbg, + Dwarf_CU_Context * cu_context, + Dwarf_Attribute attr, + Dwarf_Error *error) +{ + Dwarf_CU_Context cup; + if (attr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return (DW_DLV_ERROR); + } + + cup = attr->ar_cu_context; + if (cup == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return (DW_DLV_ERROR); + } + + if (cup->cc_dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL); + return (DW_DLV_ERROR); + } + *cu_context = cup; + *dbg = cup->cc_dbg; + return DW_DLV_OK; + +} + +int +dwarf_hasform(Dwarf_Attribute attr, + Dwarf_Half form, + Dwarf_Bool * return_bool, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_bool = (attr->ar_attribute_form == form); + return DW_DLV_OK; +} + +/* Not often called, we do not worry about efficiency here. + The dwarf_whatform() call does the sanity checks for us. +*/ +int +dwarf_whatform_direct(Dwarf_Attribute attr, + Dwarf_Half * return_form, Dwarf_Error * error) +{ + int res = dwarf_whatform(attr, return_form, error); + + if (res != DW_DLV_OK) { + return res; + } + + *return_form = attr->ar_attribute_form_direct; + return (DW_DLV_OK); +} +void * +dwarf_uncompress_integer_block( + Dwarf_Debug dbg, + Dwarf_Bool unit_is_signed, + Dwarf_Small unit_length_in_bits, + void* input_block, + Dwarf_Unsigned input_length_in_bytes, + Dwarf_Unsigned* output_length_in_units_ptr, + Dwarf_Error* error +) +{ + Dwarf_Unsigned output_length_in_units = 0; + void * output_block = 0; + int i = 0; + char * ptr = 0; + int remain = 0; + Dwarf_sfixed * array = 0; + + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_DBG_NULL); + return((void *)DW_DLV_BADADDR); + } + + if (unit_is_signed == false || + unit_length_in_bits != 32 || + input_block == NULL || + input_length_in_bytes == 0 || + output_length_in_units_ptr == NULL) { + + _dwarf_error(NULL, error, DW_DLE_BADBITC); + return ((void *) DW_DLV_BADADDR); + } + + /* At this point we assume the format is: signed 32 bit */ + + /* first uncompress everything to find the total size. */ + + output_length_in_units = 0; + remain = input_length_in_bytes; + ptr = input_block; + while (remain > 0) { + Dwarf_Signed num; + Dwarf_Word len; + num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len); + ptr += len; + remain -= len; + output_length_in_units++; + } + + if (remain != 0) { + _dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL); + return((void *)DW_DLV_BADADDR); + } + + /* then alloc */ + + output_block = (void *) + _dwarf_get_alloc(dbg, + DW_DLA_STRING, + output_length_in_units * (unit_length_in_bits / 8)); + if (output_block == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((void*)DW_DLV_BADADDR); + } + + /* then uncompress again and copy into new buffer */ + + array = (Dwarf_sfixed *) output_block; + remain = input_length_in_bytes; + ptr = input_block; + for (i=0; i<output_length_in_units && remain>0; i++) { + Dwarf_Signed num; + Dwarf_Word len; + num = _dwarf_decode_s_leb128((unsigned char *)ptr, &len); + ptr += len; + remain -= len; + array[i] = num; + } + + if (remain != 0) { + dwarf_dealloc(dbg, (unsigned char *)output_block, DW_DLA_STRING); + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return((Dwarf_P_Attribute)DW_DLV_BADADDR); + } + + *output_length_in_units_ptr = output_length_in_units; + return output_block; +} + +void +dwarf_dealloc_uncompressed_block(Dwarf_Debug dbg, void * space) +{ + dwarf_dealloc(dbg, space, DW_DLA_STRING); +} + + +int +dwarf_whatform(Dwarf_Attribute attr, + Dwarf_Half * return_form, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_form = attr->ar_attribute_form; + return (DW_DLV_OK); +} + + +/* + This function is analogous to dwarf_whatform. + It returns the attribute in attr instead of + the form. +*/ +int +dwarf_whatattr(Dwarf_Attribute attr, + Dwarf_Half * return_attr, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + + int res =get_attr_dbg(&dbg,&cu_context, attr,error); + if (res != DW_DLV_OK) { + return res; + } + *return_attr = (attr->ar_attribute); + return DW_DLV_OK; +} + + +/* Convert an offset within the local CU into a section-relative + debug_info offset. See dwarf_global_formref() and dwarf_formref() + for additional information on conversion rules. +*/ +int +dwarf_convert_to_global_offset(Dwarf_Attribute attr, + Dwarf_Off offset, Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + + switch (attr->ar_attribute_form) { + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref8: + case DW_FORM_ref_udata: + /* It would be nice to put some code to check + legality of the offset */ + /* globalize the offset */ + offset += cu_context->cc_debug_offset; + break; + + case DW_FORM_ref_addr: + /* This offset is defined to be debug_info global already, so + use this value unaltered. */ + break; + + default: + _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM); + return (DW_DLV_ERROR); + } + + *ret_offset = (offset); + return DW_DLV_OK; +} + + +/* A global offset cannot be returned by this interface: + see dwarf_global_formref(). + + DW_FORM_ref_addr is considered an incorrect form + for this call because DW_FORM_ref_addr is a global-offset into + the debug_info section. + + For the same reason DW_FORM_data4/data8 are not returned + from this function. + + For the same reason DW_FORM_sec_offset is not returned + from this function, DW_FORM_sec_offset is a global offset + (to various sections, not a CU relative offset. + + DW_FORM_ref_addr has a value which was documented in + DWARF2 as address-size but which was always an offset + so should have always been offset size (wording + corrected in DWARF3). + + November, 2010: *ret_offset is always set now. + Even in case of error. + Set to zero for most errors, but for + DW_DLE_ATTR_FORM_OFFSET_BAD + *ret_offset is set to the bad offset. */ +int +dwarf_formref(Dwarf_Attribute attr, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Unsigned maximumoffset = 0; + int res = DW_DLV_ERROR; + + + *ret_offset = 0; + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_ref1: + offset = *(Dwarf_Small *) attr->ar_debug_ptr; + break; + + case DW_FORM_ref2: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + break; + + case DW_FORM_ref4: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + break; + + case DW_FORM_ref8: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + break; + + case DW_FORM_ref_udata: + offset = _dwarf_decode_u_leb128(attr->ar_debug_ptr, NULL); + break; + case DW_FORM_ref_sig8: + /* We cannot handle this here. + The reference is to .debug_types + not a .debug_info CU local offset. */ + _dwarf_error(dbg, error, DW_DLE_REF_SIG8_NOT_HANDLED); + return (DW_DLV_ERROR); + default: + _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM); + return (DW_DLV_ERROR); + } + + /* Check that offset is within current cu portion of .debug_info. */ + + maximumoffset = cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size; + if (offset >= maximumoffset) { + /* For the DW_TAG_compile_unit is legal to have the + DW_AT_sibling attribute outside the current cu portion of + .debug_info. + In other words, sibling points to the end of the CU. + It is used for precompiled headers. + The valid condition will be: 'offset == maximumoffset'. */ + Dwarf_Half tag = 0; + if (DW_DLV_OK != dwarf_tag(attr->ar_die,&tag,error)) { + _dwarf_error(dbg, error, DW_DLE_DIE_BAD); + return (DW_DLV_ERROR); + } + + if (DW_TAG_compile_unit != tag && + DW_AT_sibling != attr->ar_attribute && + offset > maximumoffset) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + /* Return the incorrect offset for better error reporting */ + *ret_offset = (offset); + return (DW_DLV_ERROR); + } + } + *ret_offset = (offset); + return DW_DLV_OK; +} + +/* dwarf_formsig8 returns in the caller-provided 8 byte area + the 8 bytes of a DW_FORM_ref_sig8 (copying the bytes + directly to the caller). Not a string, an 8 byte + MD5 hash. This function is new in DWARF4 libdwarf. +*/ +int dwarf_formsig8(Dwarf_Attribute attr, + Dwarf_Sig8 * returned_sig_bytes, + Dwarf_Error* error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned field_end_offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Small *dataptr = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + + if(attr->ar_attribute_form != DW_FORM_ref_sig8 ) { + _dwarf_error(dbg, error, DW_DLE_BAD_REF_SIG8_FORM); + return (DW_DLV_ERROR); + } + + dataptr = cu_context->cc_is_info? dbg->de_debug_info.dss_data: + dbg->de_debug_types.dss_data; + + field_end_offset = attr->ar_debug_ptr + sizeof(Dwarf_Sig8) - + (dataptr + cu_context->cc_debug_offset); + /* Check that offset is within current cu portion of .debug_info. */ + if (field_end_offset > cu_context->cc_length + + cu_context->cc_length_size + cu_context->cc_extension_size) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + memcpy(returned_sig_bytes, attr->ar_debug_ptr, + sizeof(Dwarf_Sig8)); + return DW_DLV_OK; +} + +/* Since this returns section-relative debug_info offsets, + this can represent all REFERENCE forms correctly + and allows all applicable forms. + + DW_FORM_ref_addr has a value which was documented in + DWARF2 as address-size but which was always an offset + so should have always been offset size (wording + corrected in DWARF3). + + See the DWARF4 document for the 3 cases fitting + reference forms. The caller must determine which section the + reference 'points' to. The function added in November 2009, + dwarf_get_form_class(), helps in this regard. */ +int +dwarf_global_formref(Dwarf_Attribute attr, + Dwarf_Off * ret_offset, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + Dwarf_CU_Context cu_context = 0; + Dwarf_Half context_version = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + context_version = cu_context->cc_version_stamp; + switch (attr->ar_attribute_form) { + + case DW_FORM_ref1: + offset = *(Dwarf_Small *) attr->ar_debug_ptr; + goto fixoffset; + + case DW_FORM_ref2: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + goto fixoffset; + + case DW_FORM_ref4: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + goto fixoffset; + + case DW_FORM_ref8: + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + goto fixoffset; + + case DW_FORM_ref_udata: + offset = _dwarf_decode_u_leb128(attr->ar_debug_ptr, NULL); + + fixoffset: /* we have a local offset, make it global */ + + /* check legality of offset */ + if (offset >= cu_context->cc_length + + cu_context->cc_length_size + + cu_context->cc_extension_size) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + /* globalize the offset */ + offset += cu_context->cc_debug_offset; + break; + + /* The DWARF2 document did not make clear that + DW_FORM_data4( and 8) were references with + global offsets to some section. + That was first clearly documented in DWARF3. + In DWARF4 these two forms are no longer references. */ + case DW_FORM_data4: + if(context_version == DW_CU_VERSION4) { + _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM); + return (DW_DLV_ERROR); + } + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + /* The offset is global. */ + break; + case DW_FORM_data8: + if(context_version == DW_CU_VERSION4) { + _dwarf_error(dbg, error, DW_DLE_NOT_REF_FORM); + return (DW_DLV_ERROR); + } + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + /* The offset is global. */ + break; + case DW_FORM_ref_addr: + case DW_FORM_sec_offset: + { + /* DW_FORM_sec_offset first exists in DWARF4.*/ + /* It is up to the caller to know what the offset + of DW_FORM_sec_offset refers to, + the offset is not going to refer to .debug_info! */ + unsigned length_size = cu_context->cc_length_size; + if(length_size == 4) { + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + } else if (length_size == 8) { + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Unsigned)); + } else { + _dwarf_error(dbg, error, DW_DLE_FORM_SEC_OFFSET_LENGTH_BAD); + return (DW_DLV_ERROR); + } + } + break; + case DW_FORM_ref_sig8: /* FIXME */ + /* We cannot handle this yet. + The reference is to .debug_types, and + this function only returns an offset in + .debug_info at this point. */ + _dwarf_error(dbg, error, DW_DLE_REF_SIG8_NOT_HANDLED); + return (DW_DLV_ERROR); + default: + _dwarf_error(dbg, error, DW_DLE_BAD_REF_FORM); + return (DW_DLV_ERROR); + } + + /* We do not know what section the offset refers to, so + we have no way to check it for correctness. */ + *ret_offset = offset; + return DW_DLV_OK; +} + + +int +dwarf_formaddr(Dwarf_Attribute attr, + Dwarf_Addr * return_addr, Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_Addr ret_addr = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + if (attr->ar_attribute_form == DW_FORM_addr + /* || attr->ar_attribute_form == DW_FORM_ref_addr Allowance of + DW_FORM_ref_addr was a mistake. The value returned in that + case is NOT an address it is a global debug_info offset (ie, + not CU-relative offset within the CU in debug_info). The + Dwarf document refers to it as an address (misleadingly) in + sec 6.5.4 where it describes the reference form. It is + address-sized so that the linker can easily update it, but + it is a reference inside the debug_info section. No longer + allowed. */ + ) { + + READ_UNALIGNED(dbg, ret_addr, Dwarf_Addr, + attr->ar_debug_ptr, + cu_context->cc_address_size); + *return_addr = ret_addr; + return (DW_DLV_OK); + } + + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formflag(Dwarf_Attribute attr, + Dwarf_Bool * ret_bool, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + + if (attr == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NULL); + return (DW_DLV_ERROR); + } + + cu_context = attr->ar_cu_context; + if (cu_context == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT); + return (DW_DLV_ERROR); + } + + if (cu_context->cc_dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL); + return (DW_DLV_ERROR); + } + if (attr->ar_attribute_form == DW_FORM_flag_present) { + /* Implicit means we don't read any data at all. Just + the existence of the Form does it. DWARF4. */ + *ret_bool = 1; + return (DW_DLV_OK); + } + + if (attr->ar_attribute_form == DW_FORM_flag) { + *ret_bool = (*(Dwarf_Small *) attr->ar_debug_ptr != 0); + return (DW_DLV_OK); + } + _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formudata(Dwarf_Attribute attr, + Dwarf_Unsigned * return_uval, Dwarf_Error * error) +{ + Dwarf_Unsigned ret_value = 0; + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_data1: + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Small)); + *return_uval = ret_value; + return DW_DLV_OK; + + /* READ_UNALIGNED does the right thing as it reads + the right number bits and generates host order. + So we can just assign to *return_uval. */ + case DW_FORM_data2:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + *return_uval = ret_value; + return DW_DLV_OK; + } + + case DW_FORM_data4:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, + sizeof(Dwarf_ufixed)); + *return_uval = ret_value; + return DW_DLV_OK; + } + + case DW_FORM_data8:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Unsigned, + attr->ar_debug_ptr, + sizeof(Dwarf_Unsigned)); + *return_uval = ret_value; + return DW_DLV_OK; + } + break; + case DW_FORM_udata: + ret_value = + (_dwarf_decode_u_leb128(attr->ar_debug_ptr, NULL)); + *return_uval = ret_value; + return DW_DLV_OK; + + + /* IRIX bug 583450. We do not allow reading sdata from a udata + value. Caller can retry, calling sdata */ + + + default: + break; + } + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formsdata(Dwarf_Attribute attr, + Dwarf_Signed * return_sval, Dwarf_Error * error) +{ + Dwarf_Signed ret_value = 0; + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_data1: + *return_sval = (*(Dwarf_Sbyte *) attr->ar_debug_ptr); + return DW_DLV_OK; + + /* READ_UNALIGNED does not sign extend. + So we have to use a cast to get the + value sign extended in the right way for each case. */ + case DW_FORM_data2:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + sizeof(Dwarf_Shalf)); + *return_sval = (Dwarf_Shalf) ret_value; + return DW_DLV_OK; + + } + + case DW_FORM_data4:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + sizeof(Dwarf_sfixed)); + *return_sval = (Dwarf_sfixed) ret_value; + return DW_DLV_OK; + } + + case DW_FORM_data8:{ + READ_UNALIGNED(dbg, ret_value, Dwarf_Signed, + attr->ar_debug_ptr, + sizeof(Dwarf_Signed)); + *return_sval = (Dwarf_Signed) ret_value; + return DW_DLV_OK; + } + + case DW_FORM_sdata: + ret_value = + (_dwarf_decode_s_leb128(attr->ar_debug_ptr, NULL)); + *return_sval = ret_value; + return DW_DLV_OK; + + /* IRIX bug 583450. We do not allow reading sdata from a udata + value. Caller can retry, calling udata */ + + default: + break; + } + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + + +int +dwarf_formblock(Dwarf_Attribute attr, + Dwarf_Block ** return_block, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + Dwarf_Unsigned length = 0; + Dwarf_Small *data = 0; + Dwarf_Word leb128_length = 0; + Dwarf_Block *ret_block = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + switch (attr->ar_attribute_form) { + + case DW_FORM_block1: + length = *(Dwarf_Small *) attr->ar_debug_ptr; + data = attr->ar_debug_ptr + sizeof(Dwarf_Small); + break; + + case DW_FORM_block2: + READ_UNALIGNED(dbg, length, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_Half)); + data = attr->ar_debug_ptr + sizeof(Dwarf_Half); + break; + + case DW_FORM_block4: + READ_UNALIGNED(dbg, length, Dwarf_Unsigned, + attr->ar_debug_ptr, sizeof(Dwarf_ufixed)); + data = attr->ar_debug_ptr + sizeof(Dwarf_ufixed); + break; + + case DW_FORM_block: + length = _dwarf_decode_u_leb128(attr->ar_debug_ptr, + &leb128_length); + data = attr->ar_debug_ptr + leb128_length; + break; + + default: + _dwarf_error(cu_context->cc_dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); + } + + /* Check that block lies within current cu in .debug_info. */ + if (attr->ar_debug_ptr + length >= + dbg->de_debug_info.dss_data + cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD); + return (DW_DLV_ERROR); + } + + ret_block = (Dwarf_Block *) _dwarf_get_alloc(dbg, DW_DLA_BLOCK, 1); + if (ret_block == NULL) { + _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); + return (DW_DLV_ERROR); + } + + ret_block->bl_len = length; + ret_block->bl_data = (Dwarf_Ptr) data; + ret_block->bl_from_loclist = 0; + ret_block->bl_section_offset = data - dbg->de_debug_info.dss_data; + + + *return_block = ret_block; + return (DW_DLV_OK); +} + + +/* Contrary to long standing documentation, + The string pointer returned thru return_str must + never have dwarf_dealloc() applied to it. + Documentation fixed July 2005. +*/ +int +dwarf_formstring(Dwarf_Attribute attr, + char **return_str, Dwarf_Error * error) +{ + Dwarf_CU_Context cu_context = 0; + Dwarf_Debug dbg = 0; + Dwarf_Unsigned offset = 0; + int res = DW_DLV_ERROR; + + res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + if (attr->ar_attribute_form == DW_FORM_string) { + + void *begin = attr->ar_debug_ptr; + + if (0 == dbg->de_assume_string_in_bounds) { + /* Check that string lies within current cu in .debug_info. + */ + void *end = dbg->de_debug_info.dss_data + + cu_context->cc_debug_offset + + cu_context->cc_length + cu_context->cc_length_size + + cu_context->cc_extension_size; + if (0 == _dwarf_string_valid(begin, end)) { + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_SIZE_BAD); + return (DW_DLV_ERROR); + } + } + *return_str = (char *) (begin); + return DW_DLV_OK; + } + + if (attr->ar_attribute_form == DW_FORM_strp) { + READ_UNALIGNED(dbg, offset, Dwarf_Unsigned, + attr->ar_debug_ptr, + cu_context->cc_length_size); + + res = _dwarf_load_section(dbg, &dbg->de_debug_str,error); + if (res != DW_DLV_OK) { + return res; + } + if (0 == dbg->de_assume_string_in_bounds) { + /* Check that string lies within current cu in .debug_info. + */ + void *end = dbg->de_debug_str.dss_data + + dbg->de_debug_str.dss_size; + void*begin = dbg->de_debug_str.dss_data + offset; + if (0 == _dwarf_string_valid(begin, end)) { + _dwarf_error(dbg, error, DW_DLE_STRP_OFFSET_BAD); + return (DW_DLV_ERROR); + } + } + + /* Ensure the offset lies within the .debug_str */ + if (offset >= dbg->de_debug_str.dss_size) { + _dwarf_error(dbg, error, DW_DLE_DEBUG_STR_OFFSET_BAD); + return (DW_DLV_ERROR); + } + + *return_str = (char *) (dbg->de_debug_str.dss_data + offset); + return DW_DLV_OK; + } + + _dwarf_error(dbg, error, DW_DLE_ATTR_FORM_BAD); + return (DW_DLV_ERROR); +} + +int +dwarf_formexprloc(Dwarf_Attribute attr, + Dwarf_Unsigned * return_exprlen, + Dwarf_Ptr * block_ptr, + Dwarf_Error * error) +{ + Dwarf_Debug dbg = 0; + Dwarf_CU_Context cu_context = 0; + + int res = get_attr_dbg(&dbg,&cu_context,attr,error); + if(res != DW_DLV_OK) { + return res; + } + if (dbg == NULL) { + _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL); + return (DW_DLV_ERROR); + } + if (attr->ar_attribute_form == DW_FORM_exprloc ) { + Dwarf_Word leb_len = 0; + Dwarf_Unsigned exprlen = + (_dwarf_decode_u_leb128(attr->ar_debug_ptr, &leb_len)); + Dwarf_Small * addr = attr->ar_debug_ptr; + *return_exprlen = exprlen; + *block_ptr = addr + leb_len; + return DW_DLV_OK; + + } + _dwarf_error(dbg, error, DW_DLE_ATTR_EXPRLOC_FORM_BAD); + return (DW_DLV_ERROR); +} |