Esempio n. 1
0
/* ARGSUSED */
Dwarf_Unsigned
_dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset,
    Dwarf_Bool is_info)
{
    int local_length_size = 0;
    int local_extension_size = 0;
    Dwarf_Unsigned length = 0;
    Dwarf_Unsigned final_size = 0;
    Dwarf_Small *cuptr =
        is_info? dbg->de_debug_info.dss_data + offset:
            dbg->de_debug_types.dss_data+ offset;

    READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
        cuptr, local_length_size, local_extension_size);

    final_size = local_extension_size +  /* initial extension, if present */
        local_length_size +     /* Size of cu length field. */
        sizeof(Dwarf_Half) +    /* Size of version stamp field. */
        local_length_size +     /* Size of abbrev offset field. */
        sizeof(Dwarf_Small);    /* Size of address size field. */

    if (!is_info) {
        final_size +=
            /* type signature size */
            sizeof (Dwarf_Sig8) +
            /* type offset size */
            local_length_size;
    }
    return final_size;
}
Esempio n. 2
0
/* Read in the common cie/fde prefix, including reading
 * the cie-value which shows which this is: cie or fde.
 * */
int
dwarf_read_cie_fde_prefix(Dwarf_Debug dbg,
			  Dwarf_Small * frame_ptr_in,
			  Dwarf_Small * section_ptr_in,
			  Dwarf_Unsigned section_index_in,
			  Dwarf_Unsigned section_length_in,
			  struct cie_fde_prefix_s *data_out,
			  Dwarf_Error * error)
{
    Dwarf_Unsigned length = 0;
    int local_length_size = 0;
    int local_extension_size = 0;
    Dwarf_Small *frame_ptr = frame_ptr_in;
    Dwarf_Small *cie_ptr_addr = 0;
    Dwarf_Unsigned cie_id = 0;

    /* READ_AREA_LENGTH updates frame_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
		     frame_ptr, local_length_size,
		     local_extension_size);

    if (length % local_length_size != 0) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    if (length == 0) {
	/* nul bytes at end of section, seen at end of egcs eh_frame
	   sections (in a.out). Take this as meaning no more CIE/FDE
	   data. We should be very close to end of section. */
	return DW_DLV_NO_ENTRY;
    }

    cie_ptr_addr = frame_ptr;
    READ_UNALIGNED(dbg, cie_id, Dwarf_Unsigned,
		   frame_ptr, local_length_size);
    SIGN_EXTEND(cie_id, local_length_size);
    frame_ptr += local_length_size;

    data_out->cf_start_addr = frame_ptr_in;
    data_out->cf_addr_after_prefix = frame_ptr;

    data_out->cf_length = length;
    data_out->cf_local_length_size = local_length_size;
    data_out->cf_local_extension_size = local_extension_size;
    data_out->cf_cie_id = cie_id;
    data_out->cf_cie_id_addr = cie_ptr_addr;
    data_out->cf_section_ptr = section_ptr_in;
    data_out->cf_section_index = section_index_in;
    data_out->cf_section_length = section_length_in;
    return DW_DLV_OK;
}
Esempio n. 3
0
/* ARGSUSED */
Dwarf_Unsigned
_dwarf_length_of_cu_header(Dwarf_Debug dbg, Dwarf_Unsigned offset)
{
    int local_length_size = 0;
    int local_extension_size = 0;
    Dwarf_Unsigned length = 0;
    Dwarf_Small *cuptr = dbg->de_debug_info.dss_data + offset;

    READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
                     cuptr, local_length_size, local_extension_size);

    return local_extension_size +       /* initial extesion, if present 
                                         */
        local_length_size +     /* Size of cu length field. */
        sizeof(Dwarf_Half) +    /* Size of version stamp field. */
        local_length_size +     /* Size of abbrev offset field. */
        sizeof(Dwarf_Small);    /* Size of address size field. */

}
Esempio n. 4
0
/*  Common code for two user-visible routines to share. 
    Errors here result in memory leaks, but errors here
    are serious (making aranges unusable) so we assume
    callers will not repeat the error often or mind the leaks.
*/
static int
dwarf_get_aranges_list(Dwarf_Debug dbg,
    Dwarf_Chain  * chain_out,
    Dwarf_Signed * chain_count_out,
    Dwarf_Error  * error)
{
    /* Sweeps through the arange. */
    Dwarf_Small *arange_ptr = 0;
    Dwarf_Small *arange_ptr_start = 0;

    /*  Start of arange header.  Used for rounding offset of arange_ptr
        to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr = 0;

    /*  Version of .debug_aranges header. */
    Dwarf_Half version = 0;

    /*  Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset = 0;

    /*  Size in bytes of addresses in target. */
    Dwarf_Small address_size = 0;

    /*  Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size = 0;

    /*  Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    Dwarf_Arange arange = 0;

    /*  Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain = NULL;
    Dwarf_Chain prev_chain = NULL;
    Dwarf_Chain head_chain = NULL;
    if (!dbg->de_debug_aranges.dss_size) {
        return (DW_DLV_NO_ENTRY);
    }


    arange_ptr = dbg->de_debug_aranges.dss_data;
    arange_ptr_start = arange_ptr;
    do {
        /* Length of current set of aranges. */
        Dwarf_Unsigned length = 0;
        Dwarf_Small remainder = 0;
        Dwarf_Small *arange_ptr_past_end = 0;
        Dwarf_Unsigned range_entry_size = 0;

        int local_length_size;

        /*REFERENCED*/ /* Not used in this instance of the macro */
        int local_extension_size = 0;

        header_ptr = arange_ptr;

        /* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
        READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
            arange_ptr, local_length_size,
            local_extension_size);
        arange_ptr_past_end = arange_ptr + length;


        READ_UNALIGNED(dbg, version, Dwarf_Half,
            arange_ptr, sizeof(Dwarf_Half));
        arange_ptr += sizeof(Dwarf_Half);
        length = length - sizeof(Dwarf_Half);
        if (version != CURRENT_VERSION_STAMP) {
            _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
            return (DW_DLV_ERROR);
        }

        READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
            arange_ptr, local_length_size);
        arange_ptr += local_length_size;
        length = length - local_length_size;
        /* This applies to debug_info only, not to debug_types. */
        if (info_offset >= dbg->de_debug_info.dss_size) {
            FIX_UP_OFFSET_IRIX_BUG(dbg, info_offset,
                "arange info offset.a");
            if (info_offset >= dbg->de_debug_info.dss_size) {
                _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
                return (DW_DLV_ERROR);
            }
        }

        address_size = *(Dwarf_Small *) arange_ptr;
        if(address_size  > sizeof(Dwarf_Addr)) {
            _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR);
            return DW_DLV_ERROR;
        }
        if(address_size  ==  0) {
            _dwarf_error(dbg, error, DW_DLE_ADDRESS_SIZE_ERROR);
            return DW_DLV_ERROR;
        }
        /*  It is not an error if the sizes differ.
            Unusual, but not an error. */
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);

        /*  Even DWARF2 had a segment_size field here, meaning
            size in bytes of a segment descriptor on the target
            system. */
        segment_size = *(Dwarf_Small *) arange_ptr;
        if(segment_size > sizeof(Dwarf_Addr)) {
            _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
            return (DW_DLV_ERROR);
        }
        arange_ptr = arange_ptr + sizeof(Dwarf_Small);
        length = length - sizeof(Dwarf_Small);

        range_entry_size = 2*address_size + segment_size;
        /* Round arange_ptr offset to next multiple of address_size. */
        remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
            (range_entry_size);
        if (remainder != 0) {
            arange_ptr = arange_ptr + (2 * address_size) - remainder;
            length = length - ((2 * address_size) - remainder);
        }
        do {
            Dwarf_Addr range_address = 0;
            Dwarf_Unsigned segment_selector = 0;
            Dwarf_Unsigned range_length = 0;
            /*  For segmented address spaces, the first field to
                read is a segment selector (new in DWARF4).
                Surprising since the segment_size was always there
                in the table header! */
            if(version == 4 && segment_size != 0) {
                READ_UNALIGNED(dbg, segment_selector, Dwarf_Unsigned,
                    arange_ptr, segment_size);
                arange_ptr += address_size;
                length = length - address_size;
            }

            READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
                arange_ptr, address_size);
            arange_ptr += address_size;
            length = length - address_size;

            READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
                arange_ptr, address_size);
            arange_ptr += address_size;
            length = length - address_size;

            { 
                /*  We used to suppress all-zero entries, but
                    now we return all aranges entries so we show
                    the entire content.  March 31, 2010. */

                arange = (Dwarf_Arange)
                    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
                if (arange == NULL) {
                    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                    return (DW_DLV_ERROR);
                }

                arange->ar_segment_selector = segment_selector;
                arange->ar_segment_selector_size = segment_size;
                arange->ar_address = range_address;
                arange->ar_length = range_length;
                arange->ar_info_offset = info_offset;
                arange->ar_dbg = dbg;
                arange_count++;

                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);
                }

                curr_chain->ch_item = arange;
                if (head_chain == NULL)
                    head_chain = prev_chain = curr_chain;
                else {
                    prev_chain->ch_next = curr_chain;
                    prev_chain = curr_chain;
                }
            }
            /*  The current set of ranges is terminated by
                range_address 0 and range_length 0, but that
                does not necessarily terminate the ranges for this CU! 
                There can be multiple sets in that DWARF
                does not explicitly forbid multiple sets. 
                DWARF2,3,4 section 7.20 
                We stop short to avoid overrun of the end of the CU.  */
              
        } while (arange_ptr_past_end >= (arange_ptr + range_entry_size));

        /*  A compiler could emit some padding bytes here. dwarf2/3
            (dwarf4 sec 7.20) does not clearly make extra padding 
            bytes illegal. */
        if (arange_ptr_past_end < arange_ptr) {
            char buf[200];
            Dwarf_Unsigned pad_count = arange_ptr - arange_ptr_past_end;
            Dwarf_Unsigned offset = arange_ptr - arange_ptr_start;
            snprintf(buf,sizeof(buf),"DW_DLE_ARANGE_LENGTH_BAD."
                " 0x%" DW_PR_XZEROS DW_PR_DUx 
                " pad bytes at offset 0x%" DW_PR_XZEROS DW_PR_DUx 
                " in .debug_aranges",
                pad_count, offset);
            dwarf_insert_harmless_error(dbg,buf);
        }
        /*  For most compilers, arange_ptr == arange_ptr_past_end at
            this point. But not if there were padding bytes */
        arange_ptr = arange_ptr_past_end;
    } while (arange_ptr <
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size);

    if (arange_ptr !=
        dbg->de_debug_aranges.dss_data + dbg->de_debug_aranges.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
        return (DW_DLV_ERROR);
    }
    *chain_out = head_chain;
    *chain_count_out = arange_count;
    return DW_DLV_OK;
}
Esempio n. 5
0
/*
    This function returns the count of the number of
    aranges in the .debug_aranges section.  It sets
    aranges to point to a block of Dwarf_Arange's 
    describing the arange's.  It returns DW_DLV_ERROR
    on error.

    Must be identical in most aspects to
	dwarf_get_aranges_addr_offsets!
*/
int
dwarf_get_aranges(Dwarf_Debug dbg,
		  Dwarf_Arange ** aranges,
		  Dwarf_Signed * returned_count, Dwarf_Error * error)
{
    /* Sweeps the .debug_aranges section. */
    Dwarf_Small *arange_ptr;

    /* 
       Start of arange header.  Used for rounding offset of arange_ptr
       to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr;


    /* Version of .debug_aranges header. */
    Dwarf_Half version;

    /* Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset;

    /* Size in bytes of addresses in target. */
    Dwarf_Small address_size;

    /* Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size;

    Dwarf_Small remainder;

    /* Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    /* Start address of arange. */
    Dwarf_Addr range_address;

    /* Length of arange. */
    Dwarf_Unsigned range_length;

    Dwarf_Arange arange, *arange_block;

    Dwarf_Unsigned i;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;

    int res;

    /* ***** BEGIN CODE ***** */

    if (dbg == NULL) {
	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
	return (DW_DLV_ERROR);
    }

    res =
        _dwarf_load_section(dbg,
			    dbg->de_debug_aranges_index,
			    &dbg->de_debug_aranges,
			    error);
    if (res != DW_DLV_OK) {
        return res;
    }

    arange_ptr = dbg->de_debug_aranges;
    do {
        /* Length of current set of aranges. */
        Dwarf_Unsigned length;
	Dwarf_Small *arange_ptr_past_end = 0;

	int local_length_size;
	/*REFERENCED*/ /* Not used in this instance of the macro */
	int local_extension_size;

	header_ptr = arange_ptr;

	/* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
	READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
			 arange_ptr, local_length_size,
			 local_extension_size);
	arange_ptr_past_end = arange_ptr + length;


	READ_UNALIGNED(dbg, version, Dwarf_Half,
		       arange_ptr, sizeof(Dwarf_Half));
	arange_ptr += sizeof(Dwarf_Half);
	length = length - sizeof(Dwarf_Half);
	if (version != CURRENT_VERSION_STAMP) {
	    _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	    return (DW_DLV_ERROR);
	}

	READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
		       arange_ptr, local_length_size);
	arange_ptr += local_length_size;
	length = length - local_length_size;
	if (info_offset >= dbg->de_debug_info_size) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
	    return (DW_DLV_ERROR);
	}

	address_size = *(Dwarf_Small *) arange_ptr;
	if (address_size != dbg->de_pointer_size) {
	    /* Internal error of some kind */
	    _dwarf_error(dbg, error, DW_DLE_BADBITC);
	    return (DW_DLV_ERROR);
	}
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);

	segment_size = *(Dwarf_Small *) arange_ptr;
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);
	if (segment_size != 0) {
	    _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
	    return (DW_DLV_ERROR);
	}

	/* Round arange_ptr offset to next multiple of address_size. */
	remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
	    (2 * address_size);
	if (remainder != 0) {
	    arange_ptr = arange_ptr + (2 * address_size) - remainder;
	    length = length - ((2 * address_size) - remainder);
	}

	do {
	    READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
			   arange_ptr, address_size);
	    arange_ptr += address_size;
	    length = length - address_size;

	    READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
			   arange_ptr, address_size);
	    arange_ptr += address_size;
	    length = length - address_size;

	    if (range_address != 0 || range_length != 0) {

		arange = (Dwarf_Arange)
		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
		if (arange == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		arange->ar_address = range_address;
		arange->ar_length = range_length;
		arange->ar_info_offset = info_offset;
		arange->ar_dbg = dbg;
		arange_count++;

		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);
		}

		curr_chain->ch_item = arange;
		if (head_chain == NULL)
		    head_chain = prev_chain = curr_chain;
		else {
		    prev_chain->ch_next = curr_chain;
		    prev_chain = curr_chain;
		}
	    }
	} while (range_address != 0 || range_length != 0);

	/* A compiler could emit some padding bytes here.
	   dwarf2/3 (dwarf3 draft8 sec 7.20) does not clearly make
	   extra padding bytes illegal. */
	if(arange_ptr_past_end < arange_ptr) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
	    return (DW_DLV_ERROR);
	}
	/* For most compilers, arange_ptr == arange_ptr_past_end
	   at this point. But not if there were padding bytes */
	arange_ptr = arange_ptr_past_end;

    } while (arange_ptr <
	     dbg->de_debug_aranges + dbg->de_debug_aranges_size);

    if (arange_ptr !=
	dbg->de_debug_aranges + dbg->de_debug_aranges_size) {
	_dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
	return (DW_DLV_ERROR);
    }

    arange_block = (Dwarf_Arange *)
	_dwarf_get_alloc(dbg, DW_DLA_LIST, arange_count);
    if (arange_block == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
	*(arange_block + i) = curr_chain->ch_item;
	prev_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }

    *aranges = arange_block;
    *returned_count = (arange_count);
    return DW_DLV_OK;
}
Esempio n. 6
0
/*
    This function returns DW_DLV_OK if it succeeds
    and DW_DLV_ERR or DW_DLV_OK otherwise.
    count is set to the number of addresses in the
    .debug_aranges section. 
    For each address, the corresponding element in
    an array is set to the address itself(aranges) and
    the section offset (offsets).
    Must be identical in most aspects to
	dwarf_get_aranges!
*/
int
_dwarf_get_aranges_addr_offsets(Dwarf_Debug dbg,
				Dwarf_Addr ** addrs,
				Dwarf_Off ** offsets,
				Dwarf_Signed * count,
				Dwarf_Error * error)
{
    /* Sweeps the .debug_aranges section. */
    Dwarf_Small *arange_ptr;
    Dwarf_Small *arange_start_ptr;

    /* 
       Start of arange header.  Used for rounding offset of arange_ptr
       to twice the tuple size.  Libdwarf requirement. */
    Dwarf_Small *header_ptr;

    /* Length of current set of aranges. */
    Dwarf_Unsigned length;

    /* Version of .debug_aranges header. */
    Dwarf_Half version;

    /* Offset of current set of aranges into .debug_info. */
    Dwarf_Off info_offset;

    /* Size in bytes of addresses in target. */
    Dwarf_Small address_size;

    /* Size in bytes of segment offsets in target. */
    Dwarf_Small segment_size;

    Dwarf_Small remainder;

    /* Count of total number of aranges. */
    Dwarf_Unsigned arange_count = 0;

    /* Start address of arange. */
    Dwarf_Addr range_address;

    /* Length of arange. */
    Dwarf_Unsigned range_length;

    Dwarf_Arange arange;

    Dwarf_Unsigned i;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;

    Dwarf_Addr *arange_addrs;
    Dwarf_Off *arange_offsets;

    int res;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
	*error = NULL;

    if (dbg == NULL) {
	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
	return (DW_DLV_ERROR);
    }

    res =
        _dwarf_load_section(dbg,
			    dbg->de_debug_aranges_index,
			    &dbg->de_debug_aranges,
			    error);
    if (res != DW_DLV_OK) {
        return res;
    }

    arange_ptr = dbg->de_debug_aranges;
    do {
	int local_length_size;
	/*REFERENCED*/ /* not used in this instance of the macro */
	int local_extension_size;

	header_ptr = arange_ptr;


	/* READ_AREA_LENGTH updates arange_ptr for consumed bytes */
	READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
			 arange_ptr, local_length_size,
			 local_extension_size);


	READ_UNALIGNED(dbg, version, Dwarf_Half,
		       arange_ptr, sizeof(Dwarf_Half));
	arange_ptr += sizeof(Dwarf_Half);
	length = length - sizeof(Dwarf_Half);
	if (version != CURRENT_VERSION_STAMP) {
	    _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	    return (DW_DLV_ERROR);
	}

	READ_UNALIGNED(dbg, info_offset, Dwarf_Off,
		       arange_ptr, local_length_size);
	arange_ptr += local_length_size;
	length = length - local_length_size;
	if (info_offset >= dbg->de_debug_info_size) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_OFFSET_BAD);
	    return (DW_DLV_ERROR);
	}

	address_size = *(Dwarf_Small *) arange_ptr;
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);

	segment_size = *(Dwarf_Small *) arange_ptr;
	arange_ptr = arange_ptr + sizeof(Dwarf_Small);
	length = length - sizeof(Dwarf_Small);
	if (segment_size != 0) {
	    _dwarf_error(dbg, error, DW_DLE_SEGMENT_SIZE_BAD);
	    return (DW_DLV_ERROR);
	}

	/* Round arange_ptr offset to next multiple of address_size. */
	remainder = (Dwarf_Unsigned) (arange_ptr - header_ptr) %
	    (2 * address_size);
	if (remainder != 0) {
	    arange_ptr = arange_ptr + (2 * address_size) - remainder;
	    length = length - ((2 * address_size) - remainder);
	}

	do {
	    arange_start_ptr = arange_ptr;
	    READ_UNALIGNED(dbg, range_address, Dwarf_Addr,
			   arange_ptr, dbg->de_pointer_size);
	    arange_ptr += dbg->de_pointer_size;
	    length = length - dbg->de_pointer_size;

	    READ_UNALIGNED(dbg, range_length, Dwarf_Unsigned,
			   arange_ptr, local_length_size);
	    arange_ptr += local_length_size;
	    length = length - local_length_size;

	    if (range_address != 0 || range_length != 0) {

		arange = (Dwarf_Arange)
		    _dwarf_get_alloc(dbg, DW_DLA_ARANGE, 1);
		if (arange == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		arange->ar_address = range_address;
		arange->ar_length = range_length;
		arange->ar_info_offset =
		    arange_start_ptr - dbg->de_debug_aranges;
		arange->ar_dbg = dbg;
		arange_count++;

		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);
		}

		curr_chain->ch_item = arange;
		if (head_chain == NULL)
		    head_chain = prev_chain = curr_chain;
		else {
		    prev_chain->ch_next = curr_chain;
		    prev_chain = curr_chain;
		}
	    }
	} while (range_address != 0 || range_length != 0);

	if (length != 0) {
	    _dwarf_error(dbg, error, DW_DLE_ARANGE_LENGTH_BAD);
	    return (DW_DLV_ERROR);
	}

    } while (arange_ptr <
	     dbg->de_debug_aranges + dbg->de_debug_aranges_size);

    if (arange_ptr !=
	dbg->de_debug_aranges + dbg->de_debug_aranges_size) {
	_dwarf_error(dbg, error, DW_DLE_ARANGE_DECODE_ERROR);
	return (DW_DLV_ERROR);
    }

    arange_addrs = (Dwarf_Addr *)
	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_addrs == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }
    arange_offsets = (Dwarf_Off *)
	_dwarf_get_alloc(dbg, DW_DLA_ADDR, arange_count);
    if (arange_offsets == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < arange_count; i++) {
	Dwarf_Arange ar = curr_chain->ch_item;

	arange_addrs[i] = ar->ar_address;
	arange_offsets[i] = ar->ar_info_offset;
	prev_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, ar, DW_DLA_ARANGE);
	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }
    *count = arange_count;
    *offsets = arange_offsets;
    *addrs = arange_addrs;
    return (DW_DLV_OK);
}
Esempio n. 7
0
/*
	return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
*/
int
_dwarf_internal_printlines(Dwarf_Die die, Dwarf_Error * error)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr;
    Dwarf_Small *orig_line_ptr;

    /* 
       This points to the last byte of the .debug_line portion for the 
       current cu. */
    Dwarf_Small *line_ptr_end;

    /* 
       This points to the end of the statement program prologue for the 
       current cu, and serves to check that the prologue was correctly 
       decoded. */
    Dwarf_Small *check_line_ptr;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the 
       die. */
    Dwarf_Attribute stmt_list_attr;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset;

    /* These are the fields of the statement program header. */
    Dwarf_Unsigned total_length;
    Dwarf_Half version;
    Dwarf_Unsigned prologue_length;
    Dwarf_Small minimum_instruction_length;
    Dwarf_Small default_is_stmt;
    Dwarf_Sbyte line_base;
    Dwarf_Small line_range;
    Dwarf_Small opcode_base;

    Dwarf_Small *opcode_length;

    /* These are the state machine state variables. */
    Dwarf_Addr address;
    Dwarf_Word file;
    Dwarf_Word line;
    Dwarf_Word column;
    Dwarf_Bool is_stmt;
    Dwarf_Bool basic_block;
    Dwarf_Bool end_sequence;

    Dwarf_Sword i, file_entry_count, include_directories_count;

    /* 
       This is the current opcode read from the statement program. */
    Dwarf_Small opcode;

    /* 
       Pointer to a Dwarf_Line_Context_s structure that contains the
       context such as file names and include directories for the set
       of lines being generated. */
    Dwarf_Line_Context line_context;


    /* 
       These variables are used to decode leb128 numbers. Leb128_num
       holds the decoded number, and leb128_length is its length in
       bytes. */
    Dwarf_Word leb128_num;
    Dwarf_Word leb128_length;
    Dwarf_Sword advance_line;

    /* 
       This is the operand of the latest fixed_advance_pc extended
       opcode. */
    Dwarf_Half fixed_advance_pc;

    /* This is the length of an extended opcode instr.  */
    Dwarf_Word instr_length;
    Dwarf_Small ext_opcode;
    int local_length_size;
    /*REFERENCED*/ /* Not used in this instance of the macro */
    int local_extension_size;

    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg;
    int resattr;
    int lres;

    int res;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
	*error = NULL;

    CHECK_DIE(die, DW_DLV_ERROR)
	dbg = die->di_cu_context->cc_dbg;

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_line_index,
			   &dbg->de_debug_line,
		           error);
    if (res != DW_DLV_OK) {
	return res;
    }

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
	return resattr;
    }



    lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
	return lres;
    }

    if (line_offset >= dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
	return (DW_DLV_ERROR);
    }
    orig_line_ptr = dbg->de_debug_line;
    line_ptr = dbg->de_debug_line + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
	return resattr;
    }
    if (resattr == DW_DLV_OK) {
	int cres;
	char *cdir;

	cres = dwarf_formstring(comp_dir_attr, &cdir, error);
	if (cres == DW_DLV_ERROR) {
	    return cres;
	} else if (cres == DW_DLV_OK) {
	    comp_dir = (Dwarf_Small *) cdir;
	}
    }
    if (resattr == DW_DLV_OK) {
	dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    /* 
       Following is a straightforward decoding of the statement
       program prologue information. */

    /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
		     line_ptr, local_length_size, local_extension_size);



    line_ptr_end = line_ptr + total_length;
    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    printf("total line info length %ld bytes, "
	   "line offset 0x%llx %lld\n",
	   (long) total_length,
	   (long long) line_offset, (long long) line_offset);
    printf("compilation_directory %s\n",
	   comp_dir ? ((char *) comp_dir) : "");
    READ_UNALIGNED(dbg, version, Dwarf_Half,
		   line_ptr, sizeof(Dwarf_Half));
    line_ptr += sizeof(Dwarf_Half);
    if (version != CURRENT_VERSION_STAMP) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
		   line_ptr, local_length_size);
    line_ptr += local_length_size;
    check_line_ptr = line_ptr;

    minimum_instruction_length = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    default_is_stmt = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    line_base = *(Dwarf_Sbyte *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);

    line_range = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    opcode_base = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);
    printf("  min instruction length %d\n",
	   (int) minimum_instruction_length);
    printf("  default is stmt        %d\n", (int) default_is_stmt);
    printf("  line base              %d\n", (int) line_base);
    printf("  line_range             %d\n", (int) line_range);

    opcode_length = (Dwarf_Small *)
	alloca(sizeof(Dwarf_Small) * opcode_base);

    for (i = 1; i < opcode_base; i++) {
	opcode_length[i] = *(Dwarf_Small *) line_ptr;
	printf("  opcode[%d] length %d\n", (int) i,
	       (int) opcode_length[i]);
	line_ptr = line_ptr + sizeof(Dwarf_Small);
    }

    include_directories_count = 0;
    while ((*(char *) line_ptr) != '\0') {
	printf("  include dir[%d] %s\n",
	       (int) include_directories_count, line_ptr);
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
	include_directories_count++;
    }
    line_ptr++;

    file_entry_count = 0;
    while (*(char *) line_ptr != '\0') {

	Dwarf_Unsigned tlm2;
	Dwarf_Unsigned di;
	Dwarf_Unsigned fl;

	printf("  file[%d]  %s\n",
	       (int) file_entry_count, (char *) line_ptr);

	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

	di = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	tlm2 = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	fl = _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	printf("    dir index %d\n", (int) di);
	{
	    time_t tt = (time_t) tlm2;

	    printf("    last time 0x%x %s",	/* ctime supplies
						   newline */
		   (unsigned) tlm2, ctime(&tt));
	}
	printf("    file length %ld 0x%lx\n",
	       (long) fl, (unsigned long) fl);


	file_entry_count++;
    }
    line_ptr++;

    if (line_ptr != check_line_ptr + prologue_length) {
	_dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    /* Set up context structure for this set of lines. */
    line_context = (Dwarf_Line_Context)
	_dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
    if (line_context == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    printf("  statement prog offset in section: %lld 0x%llx\n",
	   (long long) (line_ptr - orig_line_ptr),
	   (long long) (line_ptr - orig_line_ptr));

    /* Initialize the state machine.  */
    address = 0;
    file = 1;
    line = 1;
    column = 0;
    is_stmt = default_is_stmt;
    basic_block = false;
    end_sequence = false;

    print_line_header();
    /* Start of statement program.  */
    while (line_ptr < line_ptr_end) {
	int type;

	printf(" [0x%06llx] ", (long long) (line_ptr - orig_line_ptr));
	opcode = *(Dwarf_Small *) line_ptr;
	line_ptr++;
	/* 'type' is the output */
	WHAT_IS_OPCODE(type, opcode, opcode_base,
		       opcode_length, line_ptr);



	if (type == LOP_DISCARD) {
	    /* do nothing, necessary ops done */
	} else if (type == LOP_SPECIAL) {
	    /* This op code is a special op in the object, no matter
	       that it might fall into the standard op range in this
	       compile Thatis, these are special opcodes between
	       special_opcode_base and MAX_LINE_OP_CODE.  (including
	       special_opcode_base and MAX_LINE_OP_CODE) */
	    char special[50];
	    unsigned origop = opcode;

	    opcode = opcode - opcode_base;
	    address = address + minimum_instruction_length *
		(opcode / line_range);
	    line = line + line_base + opcode % line_range;

	    sprintf(special, "Specialop %3u", origop);
	    print_line_detail(special,
			      opcode, address, (int) file, line, column,
			      is_stmt, basic_block, end_sequence);

	    basic_block = false;

	} else if (type == LOP_STANDARD) {
	    switch (opcode) {

	    case DW_LNS_copy:{
		    if (opcode_length[DW_LNS_copy] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    print_line_detail("DW_LNS_copy",
				      opcode, address, file, line,
				      column, is_stmt, basic_block,
				      end_sequence);

		    basic_block = false;
		    break;
		}

	    case DW_LNS_advance_pc:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			printf("DW_LNS_advance_pc val %lld 0x%llx\n",
			       (long long) (Dwarf_Word) utmp2,
			       (long long) (Dwarf_Word) utmp2);
		    leb128_num = (Dwarf_Word) utmp2;
		    address =
			address +
			minimum_instruction_length * leb128_num;
		    break;
		}

	    case DW_LNS_advance_line:{
		    Dwarf_Signed stmp;

		    if (opcode_length[DW_LNS_advance_line] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_SWORD(line_ptr, stmp)
			advance_line = (Dwarf_Sword) stmp;
		    printf("DW_LNS_advance_line val %lld 0x%llx\n",
			   (long long) advance_line,
			   (long long) advance_line);
		    line = line + advance_line;
		    break;
		}

	    case DW_LNS_set_file:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_file] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			file = (Dwarf_Word) utmp2;
		    printf("DW_LNS_set_file  %ld\n", (long) file);
		    break;
		}

	    case DW_LNS_set_column:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_column] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			column = (Dwarf_Word) utmp2;
		    printf("DW_LNS_set_column val %lld 0x%llx\n",
			   (long long) column, (long long) column);
		    break;
		}

	    case DW_LNS_negate_stmt:{
		    if (opcode_length[DW_LNS_negate_stmt] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    is_stmt = !is_stmt;
		    printf("DW_LNS_negate_stmt\n");
		    break;
		}

	    case DW_LNS_set_basic_block:{
		    if (opcode_length[DW_LNS_set_basic_block] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    printf("DW_LNS_set_basic_block\n");
		    basic_block = true;
		    break;
		}

	    case DW_LNS_const_add_pc:{
		    opcode = MAX_LINE_OP_CODE - opcode_base;
		    address = address + minimum_instruction_length *
			(opcode / line_range);

		    printf("DW_LNS_const_add_pc new address 0x%llx\n",
			   (long long) address);
		    break;
		}

	    case DW_LNS_fixed_advance_pc:{
		    if (opcode_length[DW_LNS_fixed_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
				   line_ptr, sizeof(Dwarf_Half));
		    line_ptr += sizeof(Dwarf_Half);
		    address = address + fixed_advance_pc;
		    printf("DW_LNS_fixed_advance_pc val %lld 0x%llx"
			   " new address 0x%llx\n",
			   (long long) fixed_advance_pc,
			   (long long) fixed_advance_pc,
			   (long long) address);
		    break;
		}
	    }

	} else if (type == LOP_EXTENDED) {
	    Dwarf_Unsigned utmp3;

	    DECODE_LEB128_UWORD(line_ptr, utmp3)
		instr_length = (Dwarf_Word) utmp3;
	    ext_opcode = *(Dwarf_Small *) line_ptr;
	    line_ptr++;
	    switch (ext_opcode) {

	    case DW_LNE_end_sequence:{
		    end_sequence = true;

		    print_line_detail("DW_LNE_end_sequence extended",
				      opcode, address, file, line,
				      column, is_stmt, basic_block,
				      end_sequence);

		    address = 0;
		    file = 1;
		    line = 1;
		    column = 0;
		    is_stmt = default_is_stmt;
		    basic_block = false;
		    end_sequence = false;

		    break;
		}

	    case DW_LNE_set_address:{
		    if (instr_length - 1 == dbg->de_pointer_size) {
			READ_UNALIGNED(dbg, address, Dwarf_Addr,
				       line_ptr, dbg->de_pointer_size);

			line_ptr += dbg->de_pointer_size;
			printf("DW_LNE_set_address address 0x%llx\n",
			       (long long) address);
		    } else {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_SET_ADDR_ERROR);
			return (DW_DLV_ERROR);
		    }

		    break;
		}

	    case DW_LNE_define_file:{


		    Dwarf_Small *fn;
		    Dwarf_Signed di;
		    Dwarf_Signed tlm;
		    Dwarf_Unsigned fl;

		    fn = (Dwarf_Small *) line_ptr;
		    line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

		    di = _dwarf_decode_u_leb128(line_ptr,
						&leb128_length);
		    line_ptr = line_ptr + leb128_length;

		    tlm =
			_dwarf_decode_u_leb128(line_ptr,
					       &leb128_length);
		    line_ptr = line_ptr + leb128_length;

		    fl = _dwarf_decode_u_leb128(line_ptr,
						&leb128_length);
		    line_ptr = line_ptr + leb128_length;


		    printf("DW_LNE_define_file %s \n", fn);
		    printf("    dir index %d\n", (int) di);
		    {
			time_t tt3 = (time_t) tlm;

			/* ctime supplies newline */
			printf("    last time 0x%x %s",
			       (unsigned) tlm, ctime(&tt3));
		    }
		    printf("    file length %ld 0x%lx\n",
			   (long) fl, (unsigned long) fl);

		    break;
		}

	    default:{
		    _dwarf_error(dbg, error,
				 DW_DLE_LINE_EXT_OPCODE_BAD);
		    return (DW_DLV_ERROR);
		}
	    }

	}
    }

    return (DW_DLV_OK);
}
Esempio n. 8
0
/* 
    Although source files is supposed to return the
    source files in the compilation-unit, it does
    not look for any in the statement program.  In
    other words, it ignores those defined using the
    extended opcode DW_LNE_define_file.
*/
int
dwarf_srcfiles(Dwarf_Die die,
	       char ***srcfiles,
	       Dwarf_Signed * srcfilecount, Dwarf_Error * error)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr;

    /* 
       This points to the last byte of the .debug_line portion for the 
       current cu. */
    Dwarf_Small *line_ptr_end;

    /* 
       This points to the end of the statement program prologue for the 
       current cu, and serves to check that the prologue was correctly 
       decoded. */
    Dwarf_Small *check_line_ptr;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the 
       die. */
    Dwarf_Attribute stmt_list_attr;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = 0;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset = 0;

    /* Some of the fields of the statement program header. */
    Dwarf_Unsigned total_length = 0;
    Dwarf_Half version = 0;
    Dwarf_Unsigned prologue_length = 0;
    Dwarf_Small special_opcode_base= 0;

    /* File name excluding included directory. */
    char *file_name = 0;

    /* Name of directory that the file is in. */
    char *dir_name = 0;

    /* Name concatenating both directory and file name. */
    char *full_name = 0;

    /* 
       This is the directory index for the file. The compilation
       directory is 0, and the first included directory is 1. */
    Dwarf_Sword dir_index = 0;

    Dwarf_Small *include_directories = 0;

    Dwarf_Sword i = 0; 
    Dwarf_Sword file_count = 0; 
    Dwarf_Sword directories_count = 0;

    /* 
       This is the current opcode read from the statement program. */

    Dwarf_Word leb128_length;

    /* This is the length of an extended opcode instr.  */

    /* 
       This points to a block of char *'s, each of which points to a
       file name. */
    char **ret_files = 0;

    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg;

    /* Used to chain the file names. */
    Dwarf_Chain curr_chain, prev_chain, head_chain = NULL;
    int resattr;
    int lres;

    int local_length_size = 0;
    /*REFERENCED*/ /* Not used in this instance of the macro */
    int local_extension_size = 0;

    int res;

    /* ***** BEGIN CODE ***** */

    /* Reset error. */
    if (error != NULL)
	*error = NULL;

    CHECK_DIE(die, DW_DLV_ERROR)
	dbg = die->di_cu_context->cc_dbg;

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
	return resattr;
    }
    
    if (dbg->de_debug_line_index == 0) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_NULL);
	return (DW_DLV_ERROR);
    }

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_line_index,
			   &dbg->de_debug_line,
			   error);
    if (res != DW_DLV_OK) {
	return res;
    }

    lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
	return lres;
    }
    if (line_offset >= dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
	return (DW_DLV_ERROR);
    }
    line_ptr = dbg->de_debug_line + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
	return resattr;
    }
    if (resattr == DW_DLV_OK) {
	int cres;
	char *cdir;

	cres = dwarf_formstring(comp_dir_attr, &cdir, error);
	if (cres == DW_DLV_ERROR) {
	    return cres;
	} else if (cres == DW_DLV_OK) {
	    comp_dir = (Dwarf_Small *) cdir;
	}
    }
    if (resattr == DW_DLV_OK) {
	dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    /* 
       Following is a straightforward decoding of the statement
       program prologue information. */
    /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
		     line_ptr, local_length_size, local_extension_size);


    line_ptr_end = line_ptr + total_length;
    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, version, Dwarf_Half,
		   line_ptr, sizeof(Dwarf_Half));
    line_ptr += sizeof(Dwarf_Half);
    if (version != CURRENT_VERSION_STAMP &&
	version != CURRENT_VERSION_STAMP3) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
		   line_ptr, local_length_size);
    line_ptr += local_length_size;
    check_line_ptr = line_ptr;

    /* Skip over minimum instruction length. */
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    /* Skip over default_is_stmt. */
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    /* Skip over line_base. */
    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);

    /* Skip over line_ptr. */
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    special_opcode_base = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    for (i = 1; i < special_opcode_base; i++) {
	/* Skip over opcode lengths for standard opcodes. */
	line_ptr = line_ptr + sizeof(Dwarf_Small);
    }

    directories_count = 0;
    include_directories = line_ptr;
    while ((*(char *) line_ptr) != '\0') {
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
	directories_count++;
    }
    line_ptr++;

    file_count = 0;
    while (*(char *) line_ptr != '\0') {
	Dwarf_Unsigned utmp;

	file_name = (char *) line_ptr;
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

	DECODE_LEB128_UWORD(line_ptr, utmp)
	    dir_index = (Dwarf_Sword) utmp;
	if (dir_index > directories_count) {
	    _dwarf_error(dbg, error, DW_DLE_DIR_INDEX_BAD);
	    return (DW_DLV_ERROR);
	}

	if (dir_index == 0)
	    dir_name = (char *) comp_dir;
	else {
	    dir_name = (char *) include_directories;
	    for (i = 1; i < dir_index; i++)
		/* FIX: this is probably very slow: redoing strlen!
		   davea 9/94 */
		dir_name = dir_name + strlen(dir_name) + 1;
	}

	/* dir_name can be NULL if there is no DW_AT_comp_dir */
	if ((*file_name) == '/' || dir_name == 0)
	    full_name = file_name;
	else {
	    full_name = (char *) _dwarf_get_alloc(dbg, DW_DLA_STRING,
						  strlen(dir_name) + 1 +
						  strlen(file_name) +
						  1);
	    if (full_name == NULL) {
		_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		return (DW_DLV_ERROR);
	    }

	    strcpy(full_name, dir_name);
	    strcat(full_name, "/");
	    strcat(full_name, file_name);
	}

	/* Skip over time of last modification. */
	_dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	/* Skip over file length. */
	_dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	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);
	}

	curr_chain->ch_item = full_name;

	if (head_chain == NULL)
	    head_chain = prev_chain = curr_chain;
	else {
	    prev_chain->ch_next = curr_chain;
	    prev_chain = curr_chain;
	}

	file_count++;
    }
    line_ptr++;

    if (line_ptr != check_line_ptr + prologue_length) {
	_dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    if (file_count == 0) {
	*srcfiles = NULL;
	*srcfilecount = 0;
	return (DW_DLV_NO_ENTRY);
    }

    ret_files = (char **)
	_dwarf_get_alloc(dbg, DW_DLA_LIST, file_count);
    if (ret_files == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < file_count; i++) {
	*(ret_files + i) = curr_chain->ch_item;
	prev_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, prev_chain, DW_DLA_CHAIN);
    }

    *srcfiles = ret_files;
    *srcfilecount = file_count;
    return (DW_DLV_OK);
}
Esempio n. 9
0
/*
	return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
*/
int
_dwarf_internal_srclines(Dwarf_Die die,
			 Dwarf_Line ** linebuf,
			 Dwarf_Signed * count,
			 Dwarf_Bool doaddrs,
			 Dwarf_Bool dolines, Dwarf_Error * error)
{
    /* 
       This pointer is used to scan the portion of the .debug_line
       section for the current cu. */
    Dwarf_Small *line_ptr;

    /* 
       This points to the last byte of the .debug_line portion for the 
       current cu. */
    Dwarf_Small *line_ptr_end;

    /* 
       This points to the end of the statement program prologue for the 
       current cu, and serves to check that the prologue was correctly 
       decoded. */
    Dwarf_Small *check_line_ptr;

    /* 
       Pointer to a DW_AT_stmt_list attribute in case it exists in the 
       die. */
    Dwarf_Attribute stmt_list_attr;

    /* Pointer to DW_AT_comp_dir attribute in die. */
    Dwarf_Attribute comp_dir_attr;

    /* Pointer to name of compilation directory. */
    Dwarf_Small *comp_dir = NULL;

    /* 
       Offset into .debug_line specified by a DW_AT_stmt_list
       attribute. */
    Dwarf_Unsigned line_offset;

    /* These are the fields of the statement program header. */
    Dwarf_Unsigned total_length;
    Dwarf_Half version;
    Dwarf_Unsigned prologue_length;
    Dwarf_Small minimum_instruction_length;
    Dwarf_Small default_is_stmt;
    Dwarf_Sbyte line_base;
    Dwarf_Small line_range;
    Dwarf_Small special_opcode_base;

    Dwarf_Small *opcode_length;
    Dwarf_Small *include_directories;
    Dwarf_File_Entry file_entries;

    /* These are the state machine state variables. */
    Dwarf_Addr address;
    Dwarf_Word file;
    Dwarf_Word line;
    Dwarf_Word column;
    Dwarf_Bool is_stmt;
    Dwarf_Bool basic_block;
    Dwarf_Bool end_sequence;

    /* 
       These pointers are used to build the list of files names by
       this cu.  cur_file_entry points to the file name being added,
       and prev_file_entry to the previous one. */
    Dwarf_File_Entry cur_file_entry, prev_file_entry;

    Dwarf_Sword i, file_entry_count, include_directories_count;

    /* 
       This is the current opcode read from the statement program. */
    Dwarf_Small opcode;

    /* 
       Pointer to a Dwarf_Line_Context_s structure that contains the
       context such as file names and include directories for the set
       of lines being generated. */
    Dwarf_Line_Context line_context;

    /* 
       This is a pointer to the current line being added to the line
       matrix. */
    Dwarf_Line curr_line;

    /* 
       These variables are used to decode leb128 numbers. Leb128_num
       holds the decoded number, and leb128_length is its length in
       bytes. */
    Dwarf_Word leb128_num;
    Dwarf_Word leb128_length;
    Dwarf_Sword advance_line;

    /* 
       This is the operand of the latest fixed_advance_pc extended
       opcode. */
    Dwarf_Half fixed_advance_pc;

    /* 
       Counts the number of lines in the line matrix. */
    Dwarf_Sword line_count = 0;

    /* This is the length of an extended opcode instr.  */
    Dwarf_Word instr_length;
    Dwarf_Small ext_opcode;

    /* 
       Used to chain together pointers to line table entries that are
       later used to create a block of Dwarf_Line entries. */
    Dwarf_Chain chain_line, head_chain = NULL, curr_chain;

    /* 
       This points to a block of Dwarf_Lines, a pointer to which is
       returned in linebuf. */
    Dwarf_Line *block_line;

    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg;
    int resattr;
    int lres;
    int local_length_size = 0;
    /*REFERENCED*/ /* Not used in this instance of the macro */
    int local_extension_size = 0;

    int res;

    /* ***** BEGIN CODE ***** */

    if (error != NULL)
	*error = NULL;

    CHECK_DIE(die, DW_DLV_ERROR)
	dbg = die->di_cu_context->cc_dbg;

    res =
       _dwarf_load_section(dbg,
		           dbg->de_debug_line_index,
			   &dbg->de_debug_line,
			   error);
    if (res != DW_DLV_OK) {
	return res;
    }

    resattr = dwarf_attr(die, DW_AT_stmt_list, &stmt_list_attr, error);
    if (resattr != DW_DLV_OK) {
	return resattr;
    }



    lres = dwarf_formudata(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
	return lres;
    }

    if (line_offset >= dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
	return (DW_DLV_ERROR);
    }
    line_ptr = dbg->de_debug_line + line_offset;
    dwarf_dealloc(dbg, stmt_list_attr, DW_DLA_ATTR);

    /* 
       If die has DW_AT_comp_dir attribute, get the string that names
       the compilation directory. */
    resattr = dwarf_attr(die, DW_AT_comp_dir, &comp_dir_attr, error);
    if (resattr == DW_DLV_ERROR) {
	return resattr;
    }
    if (resattr == DW_DLV_OK) {
	int cres;
	char *cdir;

	cres = dwarf_formstring(comp_dir_attr, &cdir, error);
	if (cres == DW_DLV_ERROR) {
	    return cres;
	} else if (cres == DW_DLV_OK) {
	    comp_dir = (Dwarf_Small *) cdir;
	}
    }
    if (resattr == DW_DLV_OK) {
	dwarf_dealloc(dbg, comp_dir_attr, DW_DLA_ATTR);
    }

    /* 
       Following is a straightforward decoding of the statement
       program prologue information. */
    /* READ_AREA_LENGTH updates line_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, total_length, Dwarf_Unsigned,
		     line_ptr, local_length_size, local_extension_size);

    line_ptr_end = line_ptr + total_length;
    if (line_ptr_end > dbg->de_debug_line + dbg->de_debug_line_size) {
	_dwarf_error(dbg, error, DW_DLE_DEBUG_LINE_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, version, Dwarf_Half,
		   line_ptr, sizeof(Dwarf_Half));
    line_ptr += sizeof(Dwarf_Half);
    if (version != CURRENT_VERSION_STAMP &&
	version != CURRENT_VERSION_STAMP3) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (DW_DLV_ERROR);
    }

    READ_UNALIGNED(dbg, prologue_length, Dwarf_Unsigned,
		   line_ptr, local_length_size);
    line_ptr += local_length_size;
    check_line_ptr = line_ptr;

    minimum_instruction_length = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    default_is_stmt = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    line_base = *(Dwarf_Sbyte *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Sbyte);

    line_range = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    special_opcode_base = *(Dwarf_Small *) line_ptr;
    line_ptr = line_ptr + sizeof(Dwarf_Small);

    opcode_length = (Dwarf_Small *)
	alloca(sizeof(Dwarf_Small) * special_opcode_base);
    for (i = 1; i < special_opcode_base; i++) {
	opcode_length[i] = *(Dwarf_Small *) line_ptr;
	line_ptr = line_ptr + sizeof(Dwarf_Small);
    }

    include_directories_count = 0;
    include_directories = line_ptr;
    while ((*(char *) line_ptr) != '\0') {
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;
	include_directories_count++;
    }
    line_ptr++;

    file_entry_count = 0;
    file_entries = prev_file_entry = NULL;
    while (*(char *) line_ptr != '\0') {

	cur_file_entry = (Dwarf_File_Entry)
	    _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
	if (cur_file_entry == NULL) {
	    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	    return (DW_DLV_ERROR);
	}

	cur_file_entry->fi_file_name = (Dwarf_Small *) line_ptr;
	line_ptr = line_ptr + strlen((char *) line_ptr) + 1;

	cur_file_entry->fi_dir_index =
	    (Dwarf_Sword) _dwarf_decode_u_leb128(line_ptr,
						 &leb128_length);
	line_ptr = line_ptr + leb128_length;

	cur_file_entry->fi_time_last_mod =
	    _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	cur_file_entry->fi_file_length =
	    _dwarf_decode_u_leb128(line_ptr, &leb128_length);
	line_ptr = line_ptr + leb128_length;

	if (file_entries == NULL)
	    file_entries = cur_file_entry;
	else
	    prev_file_entry->fi_next = cur_file_entry;
	prev_file_entry = cur_file_entry;

	file_entry_count++;
    }
    line_ptr++;

    if (line_ptr != check_line_ptr + prologue_length) {
	_dwarf_error(dbg, error, DW_DLE_LINE_PROLOG_LENGTH_BAD);
	return (DW_DLV_ERROR);
    }

    /* Set up context structure for this set of lines. */
    line_context = (Dwarf_Line_Context)
	_dwarf_get_alloc(dbg, DW_DLA_LINE_CONTEXT, 1);
    if (line_context == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    /* Initialize the state machine.  */
    address = 0;
    file = 1;
    line = 1;
    column = 0;
    is_stmt = default_is_stmt;
    basic_block = false;
    end_sequence = false;

    /* Start of statement program.  */
    while (line_ptr < line_ptr_end) {
	int type;

	opcode = *(Dwarf_Small *) line_ptr;
	line_ptr++;


	/* 'type' is the output */
	WHAT_IS_OPCODE(type, opcode, special_opcode_base,
		       opcode_length, line_ptr);



	if (type == LOP_DISCARD) {
	    /* do nothing, necessary ops done */
	} else if (type == LOP_SPECIAL) {
	    /* This op code is a special op in the object, no matter
	       that it might fall into the standard op range in this
	       compile Thatis, these are special opcodes between
	       special_opcode_base and MAX_LINE_OP_CODE.  (including
	       special_opcode_base and MAX_LINE_OP_CODE) */

	    opcode = opcode - special_opcode_base;
	    address = address + minimum_instruction_length *
		(opcode / line_range);
	    line = line + line_base + opcode % line_range;

	    if (dolines) {
		curr_line =
		    (Dwarf_Line) _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
		if (curr_line == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}

		curr_line->li_address = address;
		curr_line->li_addr_line.li_l_data.li_file =
		    (Dwarf_Sword) file;
		curr_line->li_addr_line.li_l_data.li_line =
		    (Dwarf_Sword) line;
		curr_line->li_addr_line.li_l_data.li_column =
		    (Dwarf_Half) column;
		curr_line->li_addr_line.li_l_data.li_is_stmt = is_stmt;
		curr_line->li_addr_line.li_l_data.li_basic_block =
		    basic_block;
		curr_line->li_addr_line.li_l_data.li_end_sequence =
		    end_sequence;
		curr_line->li_context = line_context;
		line_count++;

		chain_line = (Dwarf_Chain)
		    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
		if (chain_line == NULL) {
		    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
		    return (DW_DLV_ERROR);
		}
		chain_line->ch_item = curr_line;

		if (head_chain == NULL)
		    head_chain = curr_chain = chain_line;
		else {
		    curr_chain->ch_next = chain_line;
		    curr_chain = chain_line;
		}
	    }

	    basic_block = false;
	} else if (type == LOP_STANDARD) {
	    switch (opcode) {

	    case DW_LNS_copy:{
		    if (opcode_length[DW_LNS_copy] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    if (dolines) {

			curr_line =
			    (Dwarf_Line) _dwarf_get_alloc(dbg,
							  DW_DLA_LINE,
							  1);
			if (curr_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}

			curr_line->li_address = address;
			curr_line->li_addr_line.li_l_data.li_file =
			    (Dwarf_Sword) file;
			curr_line->li_addr_line.li_l_data.li_line =
			    (Dwarf_Sword) line;
			curr_line->li_addr_line.li_l_data.li_column =
			    (Dwarf_Half) column;
			curr_line->li_addr_line.li_l_data.li_is_stmt =
			    is_stmt;
			curr_line->li_addr_line.li_l_data.
			    li_basic_block = basic_block;
			curr_line->li_addr_line.li_l_data.
			    li_end_sequence = end_sequence;
			curr_line->li_context = line_context;
			line_count++;

			chain_line = (Dwarf_Chain)
			    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
			if (chain_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}
			chain_line->ch_item = curr_line;
			if (head_chain == NULL)
			    head_chain = curr_chain = chain_line;
			else {
			    curr_chain->ch_next = chain_line;
			    curr_chain = chain_line;
			}
		    }

		    basic_block = false;
		    break;
		}

	    case DW_LNS_advance_pc:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			leb128_num = (Dwarf_Word) utmp2;
		    address =
			address +
			minimum_instruction_length * leb128_num;
		    break;
		}

	    case DW_LNS_advance_line:{
		    Dwarf_Signed stmp;

		    if (opcode_length[DW_LNS_advance_line] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_SWORD(line_ptr, stmp)
			advance_line = (Dwarf_Sword) stmp;
		    line = line + advance_line;
		    break;
		}

	    case DW_LNS_set_file:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_file] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			file = (Dwarf_Word) utmp2;
		    break;
		}

	    case DW_LNS_set_column:{
		    Dwarf_Unsigned utmp2;

		    if (opcode_length[DW_LNS_set_column] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    DECODE_LEB128_UWORD(line_ptr, utmp2)
			column = (Dwarf_Word) utmp2;
		    break;
		}

	    case DW_LNS_negate_stmt:{
		    if (opcode_length[DW_LNS_negate_stmt] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    is_stmt = !is_stmt;
		    break;
		}

	    case DW_LNS_set_basic_block:{
		    if (opcode_length[DW_LNS_set_basic_block] != 0) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    basic_block = true;
		    break;
		}

	    case DW_LNS_const_add_pc:{
		    opcode = MAX_LINE_OP_CODE - special_opcode_base;
		    address = address + minimum_instruction_length *
			(opcode / line_range);

		    break;
		}

	    case DW_LNS_fixed_advance_pc:{
		    if (opcode_length[DW_LNS_fixed_advance_pc] != 1) {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_NUM_OPERANDS_BAD);
			return (DW_DLV_ERROR);
		    }

		    READ_UNALIGNED(dbg, fixed_advance_pc, Dwarf_Half,
				   line_ptr, sizeof(Dwarf_Half));
		    line_ptr += sizeof(Dwarf_Half);
		    address = address + fixed_advance_pc;
		    break;
		}
	    }

	} else if (type == LOP_EXTENDED) {
	    Dwarf_Unsigned utmp3;

	    DECODE_LEB128_UWORD(line_ptr, utmp3)
		instr_length = (Dwarf_Word) utmp3;
	    /* Dwarf_Small is a ubyte and the extended opcode
	       is a ubyte, though not stated as clearly in
	       the 2.0.0 spec as one might hope.
	    */
	    ext_opcode = *(Dwarf_Small *) line_ptr;
	    line_ptr++;
	    switch (ext_opcode) {

	    case DW_LNE_end_sequence:{
		    end_sequence = true;

		    if (dolines) {
			curr_line = (Dwarf_Line)
			    _dwarf_get_alloc(dbg, DW_DLA_LINE, 1);
			if (curr_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}

			curr_line->li_address = address;
			curr_line->li_addr_line.li_l_data.li_file =
			    (Dwarf_Sword) file;
			curr_line->li_addr_line.li_l_data.li_line =
			    (Dwarf_Sword) line;
			curr_line->li_addr_line.li_l_data.li_column =
			    (Dwarf_Half) column;
			curr_line->li_addr_line.li_l_data.li_is_stmt =
			    default_is_stmt;
			curr_line->li_addr_line.li_l_data.
			    li_basic_block = basic_block;
			curr_line->li_addr_line.li_l_data.
			    li_end_sequence = end_sequence;
			curr_line->li_context = line_context;
			line_count++;

			chain_line = (Dwarf_Chain)
			    _dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
			if (chain_line == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}
			chain_line->ch_item = curr_line;

			if (head_chain == NULL)
			    head_chain = curr_chain = chain_line;
			else {
			    curr_chain->ch_next = chain_line;
			    curr_chain = chain_line;
			}
		    }

		    address = 0;
		    file = 1;
		    line = 1;
		    column = 0;
		    is_stmt = default_is_stmt;
		    basic_block = false;
		    end_sequence = false;

		    break;
		}

	    case DW_LNE_set_address:{
		    if (instr_length - 1 == dbg->de_pointer_size) {
			READ_UNALIGNED(dbg, address, Dwarf_Addr,
				       line_ptr, dbg->de_pointer_size);
			if (doaddrs) {
			    curr_line =
				(Dwarf_Line) _dwarf_get_alloc(dbg,
							      DW_DLA_LINE,
							      1);
			    if (curr_line == NULL) {
				_dwarf_error(dbg, error,
					     DW_DLE_ALLOC_FAIL);
				return (DW_DLV_ERROR);
			    }

			    curr_line->li_address = address;
			    curr_line->li_addr_line.li_offset =
				line_ptr - dbg->de_debug_line;

			    line_count++;

			    chain_line = (Dwarf_Chain)
				_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
			    if (chain_line == NULL) {
				_dwarf_error(dbg, error,
					     DW_DLE_ALLOC_FAIL);
				return (DW_DLV_ERROR);
			    }
			    chain_line->ch_item = curr_line;

			    if (head_chain == NULL)
				head_chain = curr_chain = chain_line;
			    else {
				curr_chain->ch_next = chain_line;
				curr_chain = chain_line;
			    }
			}

			line_ptr += dbg->de_pointer_size;
		    } else {
			_dwarf_error(dbg, error,
				     DW_DLE_LINE_SET_ADDR_ERROR);
			return (DW_DLV_ERROR);
		    }

		    break;
		}

	    case DW_LNE_define_file:{

		    if (dolines) {
			cur_file_entry = (Dwarf_File_Entry)
			    _dwarf_get_alloc(dbg, DW_DLA_FILE_ENTRY, 1);
			if (cur_file_entry == NULL) {
			    _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
			    return (DW_DLV_ERROR);
			}

			cur_file_entry->fi_file_name =
			    (Dwarf_Small *) line_ptr;
			line_ptr =
			    line_ptr + strlen((char *) line_ptr) + 1;

			cur_file_entry->fi_dir_index =
			    (Dwarf_Sword)
			    _dwarf_decode_u_leb128(line_ptr,
						   &leb128_length);
			line_ptr = line_ptr + leb128_length;

			cur_file_entry->fi_time_last_mod =
			    _dwarf_decode_u_leb128(line_ptr,
						   &leb128_length);
			line_ptr = line_ptr + leb128_length;

			cur_file_entry->fi_file_length =
			    _dwarf_decode_u_leb128(line_ptr,
						   &leb128_length);
			line_ptr = line_ptr + leb128_length;

			if (file_entries == NULL)
			    file_entries = cur_file_entry;
			else
			    prev_file_entry->fi_next = cur_file_entry;
			prev_file_entry = cur_file_entry;

			file_entry_count++;
		    }
		    break;
		}

	    default:{
		    _dwarf_error(dbg, error,
				 DW_DLE_LINE_EXT_OPCODE_BAD);
		    return (DW_DLV_ERROR);
		}
	    }

	}
    }

    block_line = (Dwarf_Line *)
	_dwarf_get_alloc(dbg, DW_DLA_LIST, line_count);
    if (block_line == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    curr_chain = head_chain;
    for (i = 0; i < line_count; i++) {
	*(block_line + i) = curr_chain->ch_item;
	head_chain = curr_chain;
	curr_chain = curr_chain->ch_next;
	dwarf_dealloc(dbg, head_chain, DW_DLA_CHAIN);
    }

    line_context->lc_file_entries = file_entries;
    line_context->lc_file_entry_count = file_entry_count;
    line_context->lc_include_directories = include_directories;
    line_context->lc_include_directories_count =
	include_directories_count;
    line_context->lc_line_count = line_count;
    line_context->lc_compilation_directory = comp_dir;
    line_context->lc_version_number = version;	
    line_context->lc_dbg = dbg;
    *count = line_count;

    *linebuf = block_line;
    return (DW_DLV_OK);
}
Esempio n. 10
0
/* Sweeps the complete  section. 
*/
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			*pubnames_like_ptr;



	/* 
	    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_Half			version;

	/* 
	    Offset from the start of compilation-unit 
	    for the current global.
	*/
    Dwarf_Off			die_offset_in_cu;

    Dwarf_Unsigned		global_count = 0;

	/* Points to the current global read. */
    Dwarf_Global		global;

	/* 
	    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;

	/* Points to contiguous block of Dwarf_Global's to be returned. */
    Dwarf_Global		*ret_globals;

	/* Temporary counter. */
    Dwarf_Unsigned		i;

    


    if (dbg == NULL) {
	_dwarf_error(NULL, error, DW_DLE_DBG_NULL); 
	return(DW_DLV_ERROR);
    }

    if (section_data_ptr == NULL) {
	return(DW_DLV_NO_ENTRY);
    }

    pubnames_like_ptr = section_data_ptr;
    do {
        Dwarf_Unsigned length;
	int local_extension_size;
	int local_length_size;

	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;


	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);
	    }
	}

    } 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);
    if (ret_globals == NULL) 
	{_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL); return(DW_DLV_ERROR);}

	/* 
	    Store pointers to Dwarf_Global_s structs in
	    contiguous block, 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);
    }

    *globals = ret_globals;
    *return_count = (global_count);
    return DW_DLV_OK;
}
Esempio n. 11
0
/*  This function is used to create a CU Context for
    a compilation-unit that begins at offset in 
    .debug_info.  The CU Context is attached to the
    list of CU Contexts for this dbg.  It is assumed
    that the CU at offset has not been read before,
    and so do not call this routine before making
    sure of this with _dwarf_find_CU_Context().
    Returns NULL on error.  As always, being an
    internal routine, assumes a good dbg.

    This function must always set a dwarf error code
    before returning NULL. Always.  */
static Dwarf_CU_Context
_dwarf_make_CU_Context(Dwarf_Debug dbg,
    Dwarf_Off offset,Dwarf_Bool is_info,Dwarf_Error * error)
{
    Dwarf_CU_Context cu_context = 0;
    Dwarf_Unsigned length = 0;
    Dwarf_Signed abbrev_offset = 0;
    Dwarf_Unsigned typeoffset = 0;
    Dwarf_Sig8 signaturedata;
    Dwarf_Unsigned types_extra_len = 0;
    Dwarf_Byte_Ptr cu_ptr = 0;
    int local_extension_size = 0;
    int local_length_size = 0;
    Dwarf_Debug_InfoTypes dis = is_info? &dbg->de_info_reading: 
        &dbg->de_types_reading; 
    Dwarf_Unsigned section_size = is_info? dbg->de_debug_info.dss_size:
        dbg->de_debug_types.dss_size;

    cu_context =
        (Dwarf_CU_Context) _dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1);
    if (cu_context == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (NULL);
    }
    cu_context->cc_dbg = dbg;
    cu_context->cc_is_info = is_info;

    {
        Dwarf_Small *dataptr = is_info? dbg->de_debug_info.dss_data:
            dbg->de_debug_types.dss_data;
        cu_ptr = (Dwarf_Byte_Ptr) (dataptr+offset);
    }

    /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
        cu_ptr, local_length_size, local_extension_size);
    cu_context->cc_length_size = local_length_size;
    cu_context->cc_extension_size = local_extension_size;


    cu_context->cc_length = (Dwarf_Word) length;

    READ_UNALIGNED(dbg, cu_context->cc_version_stamp, Dwarf_Half,
        cu_ptr, sizeof(Dwarf_Half));
    cu_ptr += sizeof(Dwarf_Half);

    READ_UNALIGNED(dbg, abbrev_offset, Dwarf_Signed,
        cu_ptr, local_length_size);
    cu_ptr += local_length_size;
    cu_context->cc_abbrev_offset = (Dwarf_Sword) abbrev_offset;

    cu_context->cc_address_size = *(Dwarf_Small *) cu_ptr;
    ++cu_ptr;
    
    

    if(cu_context->cc_address_size  > sizeof(Dwarf_Addr)) {
        _dwarf_error(dbg, error, DW_DLE_CU_ADDRESS_SIZE_BAD);
        return (NULL);
    }
    if(!is_info) {
        /* debug_types CU headers have extra header bytes. */
        types_extra_len = sizeof(signaturedata) + local_length_size;
    }
    if ((length < (CU_VERSION_STAMP_SIZE + local_length_size + 
        CU_ADDRESS_SIZE_SIZE + types_extra_len)) ||
        ((offset + length + local_length_size + local_extension_size) > 
            section_size)) {

        dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
        _dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR);
        return (NULL);
    }

    if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP
        && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP3
        && cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) {
        dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
        _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
        return (NULL);
    }
    if (!is_info) {
        if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP4) {
            dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_TYPES_ONLY_DWARF4);
            return (NULL);
        }
        /*  Now read the debug_types extra header fields of
            the signature (8 bytes) and the typeoffset. */
        memcpy(&signaturedata,cu_ptr,sizeof(signaturedata));
        cu_ptr += sizeof(signaturedata);
        READ_UNALIGNED(dbg, typeoffset, Dwarf_Unsigned,
            cu_ptr, local_length_size);
        cu_context->cc_typeoffset = typeoffset;
        cu_context->cc_signature = signaturedata;
        Dwarf_Unsigned cu_len = length - (local_length_size + 
            local_extension_size);
        if(typeoffset >= cu_len) {
            dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_TYPEOFFSET_BAD);
            return (NULL);
        }
    }

    if (abbrev_offset >= dbg->de_debug_abbrev.dss_size) {
        dwarf_dealloc(dbg, cu_context, DW_DLA_CU_CONTEXT);
        _dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR);
        return (NULL);
    }

    cu_context->cc_abbrev_hash_table =
        (Dwarf_Hash_Table) _dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE, 1);
    if (cu_context->cc_abbrev_hash_table == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (NULL);
    }

    cu_context->cc_debug_offset = (Dwarf_Word) offset;

    dis->de_last_offset = (Dwarf_Word) (offset + length +
        local_extension_size + local_length_size);

    if (dis->de_cu_context_list == NULL) {
        dis->de_cu_context_list = cu_context;
        dis->de_cu_context_list_end = cu_context;
    } else {
        dis->de_cu_context_list_end->cc_next = cu_context;
        dis->de_cu_context_list_end = cu_context;
    }

    return (cu_context);
}
Esempio n. 12
0
/*
    This function is used to create a CU Context for
    a compilation-unit that begins at offset in 
    .debug_info.  The CU Context is attached to the
    list of CU Contexts for this dbg.  It is assumed
    that the CU at offset has not been read before,
    and so do not call this routine before making
    sure of this with _dwarf_find_CU_Context().
    Returns NULL on error.  As always, being an
    internal routine, assumes a good dbg.

    This function must always set a dwarf error code
    before returning NULL. Always.
*/
static Dwarf_CU_Context
_dwarf_make_CU_Context(Dwarf_Debug dbg,
		       Dwarf_Off offset, Dwarf_Error * error)
{
    Dwarf_CU_Context cu_context;
    Dwarf_Unsigned length;
    Dwarf_Signed abbrev_offset;
    Dwarf_Byte_Ptr cu_ptr;
    int local_extension_size = 0;
    int local_length_size;

    cu_context =
	(Dwarf_CU_Context) _dwarf_get_alloc(dbg, DW_DLA_CU_CONTEXT, 1);
    if (cu_context == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (NULL);
    }
    cu_context->cc_dbg = dbg;

    cu_ptr = (Dwarf_Byte_Ptr) (dbg->de_debug_info + offset);

    /* READ_AREA_LENGTH updates cu_ptr for consumed bytes */
    READ_AREA_LENGTH(dbg, length, Dwarf_Unsigned,
		     cu_ptr, local_length_size, local_extension_size);
    cu_context->cc_length_size = local_length_size;
    cu_context->cc_extension_size = local_extension_size;


    cu_context->cc_length = (Dwarf_Word) length;

    READ_UNALIGNED(dbg, cu_context->cc_version_stamp, Dwarf_Half,
		   cu_ptr, sizeof(Dwarf_Half));
    cu_ptr += sizeof(Dwarf_Half);

    READ_UNALIGNED(dbg, abbrev_offset, Dwarf_Signed,
		   cu_ptr, local_length_size);
    cu_ptr += local_length_size;
    cu_context->cc_abbrev_offset = (Dwarf_Sword) abbrev_offset;

    cu_context->cc_address_size = *(Dwarf_Small *) cu_ptr;

    if ((length < CU_VERSION_STAMP_SIZE + local_length_size +
	 CU_ADDRESS_SIZE_SIZE) ||
	(offset + length + local_length_size +
	 local_extension_size > dbg->de_debug_info_size)) {

	_dwarf_error(dbg, error, DW_DLE_CU_LENGTH_ERROR);
	return (NULL);
    }

    if (cu_context->cc_address_size != dbg->de_pointer_size) {
	_dwarf_error(dbg, error, DW_DLE_CU_ADDRESS_SIZE_BAD);
	return (NULL);
    }

    if (cu_context->cc_version_stamp != CURRENT_VERSION_STAMP
	&& cu_context->cc_version_stamp != CURRENT_VERSION_STAMP3) {
	_dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
	return (NULL);
    }

    if (abbrev_offset >= dbg->de_debug_abbrev_size) {
	_dwarf_error(dbg, error, DW_DLE_ABBREV_OFFSET_ERROR);
	return (NULL);
    }

    cu_context->cc_abbrev_hash_table =
	(Dwarf_Hash_Table) _dwarf_get_alloc(dbg, DW_DLA_HASH_TABLE, 1);
    if (cu_context->cc_abbrev_hash_table == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (NULL);
    }

    cu_context->cc_debug_info_offset = (Dwarf_Word) offset;
    dbg->de_info_last_offset =
	(Dwarf_Word) (offset + length +
		      local_extension_size + local_length_size);

    if (dbg->de_cu_context_list == NULL) {
	dbg->de_cu_context_list = cu_context;
	dbg->de_cu_context_list_end = cu_context;
    } else {
	dbg->de_cu_context_list_end->cc_next = cu_context;
	dbg->de_cu_context_list_end = cu_context;
    }

    return (cu_context);
}