예제 #1
0
/* 
    This function performs error handling as described in the 
    libdwarf consumer document section 3.  Dbg is the Dwarf_debug
    structure being processed.  Error is a pointer to the pointer
    to the error descriptor that will be returned.  Errval is an
    error code listed in dwarf_error.h.
*/
void
_dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, Dwarf_Sword errval)
{
    Dwarf_Error errptr;

    /* 
       Allow NULL dbg on entry, since sometimes that can happen and we
       want to report the upper-level error, not this one. */
    if (error != NULL) {

        /* 
           If dbg is NULL, use the alternate error struct. However,
           this will overwrite the earlier error. */
        if (dbg != NULL) {
            errptr =
                (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
            if (errptr == NULL) {
                fprintf(stderr,
                        "Could not allocate Dwarf_Error structure, "
                        "abort() in libdwarf.\n");
                abort();
            }
        } else {
            /* We have no dbg to work with. dwarf_init failed. We hack
               up a special area. */
            errptr = _dwarf_special_no_dbg_error_malloc();
            if (errptr == NULL) {
                fprintf(stderr,
                        "Could not allocate Dwarf_Error structure, "
                        "abort() in libdwarf..\n");
                abort();
            }
        }

        errptr->er_errval = errval;
        *error = errptr;
        return;
    }

    if (dbg != NULL && dbg->de_errhand != NULL) {
        errptr = (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
        if (errptr == NULL) {
            fprintf(stderr, "Could not allocate Dwarf_Error structure,"
                    " abort() in libdwarf.\n");
            abort();
        }
        errptr->er_errval = errval;
        dbg->de_errhand(errptr, dbg->de_errarg);
        return;
    }
    fprintf(stderr,
            "abort() in libdwarf. No error argument, no handler.\n");
    abort();
}
예제 #2
0
/*  This function performs error handling as described in the
    libdwarf consumer document section 3.  Dbg is the Dwarf_debug
    structure being processed.  Error is a pointer to the pointer
    to the error descriptor that will be returned.  Errval is an
    error code listed in dwarf_error.h.

    If the malloc arena is exhausted we return a pointer to
    a special static error record.  This special singleton
    is mostly ignored by dwarf_dealloc().
    Users should not be storing Dwarf_Error pointers
    for long so this singleton is only going to cause
    confusion when callers try to save an out-of-memory
    Dwarf_Error pointer.
    The _dwarf_failsafe_error is intended to
    be an improvement over an abort() call.
    The failsafe means we will not abort due to
    a Dwarf_Error struct creation.
*/
void
_dwarf_error(Dwarf_Debug dbg, Dwarf_Error * error, Dwarf_Sword errval)
{
    Dwarf_Error errptr;

    /*  Allow NULL dbg on entry, since sometimes that can happen and we
        want to report the upper-level error, not this one. */
    if (error != NULL) {
        /*  If dbg is NULL, use the alternate error struct. However,
            this will overwrite the earlier error. */
        if (dbg != NULL) {
            errptr =
                (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
            if (!errptr) {
                errptr = &_dwarf_failsafe_error;
                errptr->er_static_alloc = DE_STATIC;
            } else {
                errptr->er_static_alloc = DE_STANDARD;
            }
        } else {
            /*  We have no dbg to work with. dwarf_init failed. We hack
                up a special area. */
            errptr = _dwarf_special_no_dbg_error_malloc();
            if (!errptr) {
                errptr = &_dwarf_failsafe_error;
                errptr->er_static_alloc = DE_STATIC;
            } else {
                errptr->er_static_alloc = DE_MALLOC;
            }
        }
        errptr->er_errval = errval;
        *error = errptr;
        return;
    }

    if (dbg != NULL && dbg->de_errhand != NULL) {
        errptr = (Dwarf_Error) _dwarf_get_alloc(dbg, DW_DLA_ERROR, 1);
        if (errptr == NULL) {
            errptr = &_dwarf_failsafe_error;
            errptr->er_static_alloc = DE_STATIC;
        }
        errptr->er_errval = errval;
        dbg->de_errhand(errptr, dbg->de_errarg);
        return;
    }
    fflush(stdout);
    fprintf(stdout,
        "\nNow abort() in libdwarf. "
        "No error argument or handler available.\n");
    fflush(stdout);
    abort();
}
예제 #3
0
/*
        Return DW_DLV_OK or, if error,
        DW_DLV_ERROR.

        Thru pointers, return 2 arrays and a count
        for rqs.
*/
int
_dwarf_line_address_offsets(Dwarf_Debug dbg,
                            Dwarf_Die die,
                            Dwarf_Addr ** addrs,
                            Dwarf_Off ** offs,
                            Dwarf_Unsigned * returncount,
                            Dwarf_Error * err)
{
    Dwarf_Addr *laddrs;
    Dwarf_Off *loffsets;
    Dwarf_Signed lcount;
    Dwarf_Signed i;
    int res;
    Dwarf_Line *linebuf;

    res = _dwarf_internal_srclines(die, &linebuf, &lcount,      /* addrlist= 
                                                                 */ true,
                                   /* linelist= */ false, err);
    if (res != DW_DLV_OK) {
        return res;
    }
    laddrs = (Dwarf_Addr *)
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
    if (laddrs == NULL) {
        dwarf_srclines_dealloc(dbg, linebuf, lcount);
        _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    loffsets = (Dwarf_Off *)
        _dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
    if (loffsets == NULL) {
        dwarf_srclines_dealloc(dbg, linebuf, lcount);
        /* We already allocated what laddrs points at, so we'e better
           deallocate that space since we are not going to return the
           pointer to the caller. */
        dwarf_dealloc(dbg, laddrs, DW_DLA_ADDR);
        _dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }

    for (i = 0; i < lcount; i++) {
        laddrs[i] = linebuf[i]->li_address;
        loffsets[i] = linebuf[i]->li_addr_line.li_offset;
    }
    dwarf_srclines_dealloc(dbg, linebuf, lcount);
    *returncount = lcount;
    *offs = loffsets;
    *addrs = laddrs;
    return DW_DLV_OK;
}
예제 #4
0
static int
_dwarf_macro_stack_push_index(Dwarf_Debug dbg, Dwarf_Signed indx,
                              struct macro_stack_s *ms)
{
    Dwarf_Signed *newbase;

    if (ms->next_to_use >= ms->max) {
        long new_size;

        if (ms->max == 0) {
            ms->max = STARTERMAX;
        }
        new_size = ms->max * 2;
        newbase =
            (Dwarf_Signed *)_dwarf_get_alloc(dbg, DW_DLA_STRING,
                                             new_size * sizeof(Dwarf_Signed));
        if (newbase == 0) {
            /* just leave the old array in place */
            ms->was_fault = 1;
            return DW_DLV_ERROR;
        }
        if (ms->st_base) {
            memcpy(newbase, ms->st_base,
                   ms->next_to_use * sizeof(Dwarf_Signed));
            dwarf_dealloc(dbg, ms->st_base, DW_DLA_STRING);
        }
        ms->st_base = newbase;
        ms->max = new_size;
    }
    ms->st_base[ms->next_to_use] = indx;
    ++ms->next_to_use;
    return DW_DLV_OK;
}
예제 #5
0
/*
	Return DW_DLV_OK or, if error,
	DW_DLV_ERROR.

	Thru pointers, return 2 arrays and a count
	for rqs.
*/
int
_dwarf_line_address_offsets(Dwarf_Debug dbg,
			    Dwarf_Die die,
			    Dwarf_Addr ** addrs,
			    Dwarf_Off ** offs,
			    Dwarf_Unsigned * returncount,
			    Dwarf_Error * err)
{
    Dwarf_Addr *laddrs;
    Dwarf_Off *loffsets;
    Dwarf_Signed lcount;
    Dwarf_Signed i;
    int res;
    Dwarf_Line *linebuf;

    res = _dwarf_internal_srclines(die, &linebuf,
				   &lcount, /* addrlist= */ true,
				   /* linelist= */ false, err);
    if (res != DW_DLV_OK) {
	return res;
    }
    laddrs = (Dwarf_Addr *)
	_dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
    if (laddrs == NULL) {
	_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }
    loffsets = (Dwarf_Off *)
	_dwarf_get_alloc(dbg, DW_DLA_ADDR, lcount);
    if (loffsets == NULL) {
	_dwarf_error(dbg, err, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    for (i = 0; i < lcount; i++) {
	laddrs[i] = linebuf[i]->li_address;
	loffsets[i] = linebuf[i]->li_addr_line.li_offset;
	dwarf_dealloc(dbg, linebuf[i], DW_DLA_LINE);
    }
    dwarf_dealloc(dbg, linebuf, DW_DLA_LIST);
    *returncount = lcount;
    *offs = loffsets;
    *addrs = laddrs;
    return DW_DLV_OK;
}
예제 #6
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)
{
    /* Count of total number of aranges. */
    Dwarf_Signed arange_count = 0;

    Dwarf_Arange *arange_block = 0;

    /* Used to chain Dwarf_Aranges structs. */
    Dwarf_Chain curr_chain = NULL;
    Dwarf_Chain prev_chain = NULL;
    Dwarf_Chain head_chain = NULL;
    Dwarf_Unsigned i = 0;
    int res = DW_DLV_ERROR;

    /* ***** 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, error);
    if (res != DW_DLV_OK) {
        return res;
    }

    res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
    if(res != DW_DLV_OK) {
        return res;
    }

    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;
}
예제 #7
0
/*  Handles simple location entries and loclists.
    Returns all the Locdesc's thru llbuf.

    Will not work properly for DWARF5 and may not
    work for some recent versions of gcc or llvm emitting
    DWARF4 with location extensions.

    Does not work for .debug_loc.dwo

    Use dwarf_get_loclist_b() and associated functions.
*/
int
dwarf_loclist_n(Dwarf_Attribute attr,
    Dwarf_Locdesc *** llbuf_out,
    Dwarf_Signed * listlen_out, Dwarf_Error * error)
{
    Dwarf_Debug dbg;

    /*  Dwarf_Attribute that describes the DW_AT_location in die, if
        present. */
    Dwarf_Attribute loc_attr = attr;

    /* Dwarf_Block that describes a single location expression. */
    Dwarf_Block_c loc_block;

    /* A pointer to the current Dwarf_Locdesc read. */
    Dwarf_Locdesc *locdesc = 0;

    Dwarf_Half form = 0;
    Dwarf_Addr lowpc = 0;
    Dwarf_Addr highpc = 0;
    Dwarf_Signed listlen = 0;
    Dwarf_Locdesc **llbuf = 0;
    Dwarf_CU_Context cucontext = 0;
    unsigned address_size = 0;
    int cuvstamp = 0;
    Dwarf_Bool is_cu = FALSE;

    int blkres = DW_DLV_ERROR;
    int setup_res = DW_DLV_ERROR;

    /* ***** BEGIN CODE ***** */
    setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
    if (setup_res != DW_DLV_OK) {
        return setup_res;
    }
    cuvstamp = cucontext->cc_version_stamp;
    address_size = cucontext->cc_address_size;
    /*  If this is a form_block then it's a location expression. If it's
        DW_FORM_data4 or DW_FORM_data8  in DWARF2 or DWARF3
        (or in DWARF4 or 5 a DW_FORM_sec_offset) it's a loclist offset */
    if (cuvstamp == DW_CU_VERSION5) {
        /* Use a newer interface. */
        _dwarf_error(dbg, error, DW_DLE_LOCLIST_INTERFACE_ERROR);
        return (DW_DLV_ERROR);
    }
    if (((cuvstamp == DW_CU_VERSION2 || cuvstamp == DW_CU_VERSION3) &&
        (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
        ((cuvstamp == DW_CU_VERSION4) && form == DW_FORM_sec_offset)) {

        setup_res = context_is_cu_not_tu(cucontext,&is_cu,error);
        if(setup_res != DW_DLV_OK) {
            return setup_res;
        }
        /*  A reference to .debug_loc, with an offset in .debug_loc of a
            loclist */
        Dwarf_Unsigned loclist_offset = 0;
        int off_res  = DW_DLV_ERROR;
        int count_res = DW_DLV_ERROR;
        int loclist_count = 0;
        int lli = 0;

        off_res = _dwarf_get_loclist_header_start(dbg,
            attr, &loclist_offset, error);
        if (off_res != DW_DLV_OK) {
            return off_res;
        }
        count_res = _dwarf_get_loclist_count(dbg, loclist_offset,
            address_size, &loclist_count, error);
        listlen = loclist_count;
        if (count_res != DW_DLV_OK) {
            return count_res;
        }
        if (loclist_count == 0) {
            return DW_DLV_NO_ENTRY;
        }

        llbuf = (Dwarf_Locdesc **)
            _dwarf_get_alloc(dbg, DW_DLA_LIST, loclist_count);
        if (!llbuf) {
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return (DW_DLV_ERROR);
        }

        for (lli = 0; lli < loclist_count; ++lli) {
            int lres = 0;
            blkres = _dwarf_read_loc_section(dbg, &loc_block,
                &lowpc,
                &highpc,
                loclist_offset,
                address_size,
                error);
            if (blkres != DW_DLV_OK) {
                _dwarf_cleanup_llbuf(dbg, llbuf, lli);
                return (blkres);
            }
            lres = _dwarf_get_locdesc(dbg, &loc_block,
                address_size,
                cucontext->cc_length_size,
                cucontext->cc_version_stamp,
                lowpc, highpc,
                &locdesc,
                error);
            if (lres != DW_DLV_OK) {
                _dwarf_cleanup_llbuf(dbg, llbuf, lli);
                /* low level error already set: let it be passed back */
                return lres;
            }
            llbuf[lli] = locdesc;

            /* Now get to next loclist entry offset. */
            loclist_offset = loc_block.bl_section_offset +
                loc_block.bl_len;
        }
    } else {
        if( form == DW_FORM_exprloc) {
            blkres = dwarf_formexprloc(loc_attr,&loc_block.bl_len,
                &loc_block.bl_data,error);
            if(blkres != DW_DLV_OK) {
                return blkres;
            }
            loc_block.bl_from_loclist = 0;
            loc_block.bl_section_offset  =
                (char *)loc_block.bl_data -
                (char *)dbg->de_debug_info.dss_data;
        } else {
            Dwarf_Block *tblock = 0;
            blkres = dwarf_formblock(loc_attr, &tblock, error);
            if (blkres != DW_DLV_OK) {
                return (blkres);
            }
            loc_block.bl_len = tblock->bl_len;;
            loc_block.bl_data = tblock->bl_data;
            loc_block.bl_from_loclist = tblock->bl_from_loclist;
            loc_block.bl_section_offset = tblock->bl_section_offset;
            loc_block.bl_locdesc_offset = 0; /* not relevent */
            /*  We copied tblock contents to the stack var, so can dealloc
                tblock now.  Avoids leaks. */
            dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
        }
        listlen = 1; /* One by definition of a location entry. */
        lowpc = 0;   /* HACK */
        highpc = (Dwarf_Unsigned) (-1LL); /* HACK */

        /*  An empty location description (block length 0) means the
            code generator emitted no variable, the variable was not
            generated, it was unused or perhaps never tested after being
            set. Dwarf2, section 2.4.1 In other words, it is not an
            error, and we don't test for block length 0 specially here. */
        blkres = _dwarf_get_locdesc(dbg, &loc_block,
            address_size,
            cucontext->cc_length_size,
            cucontext->cc_version_stamp,
            lowpc, highpc,
            &locdesc,
            error);
        if (blkres != DW_DLV_OK) {
            /* low level error already set: let it be passed back */
            return blkres;
        }
        llbuf = (Dwarf_Locdesc **)
            _dwarf_get_alloc(dbg, DW_DLA_LIST, listlen);
        if (!llbuf) {
            /* Free the locdesc we allocated but won't use. */
            dwarf_dealloc(dbg, locdesc, DW_DLA_LOCDESC);
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return (DW_DLV_ERROR);
        }
        llbuf[0] = locdesc;
    }

    *llbuf_out = llbuf;
    *listlen_out = listlen;
    return (DW_DLV_OK);
}
예제 #8
0
int
dwarf_get_abbrev(Dwarf_Debug dbg,
		 Dwarf_Unsigned offset,
		 Dwarf_Abbrev * returned_abbrev,
		 Dwarf_Unsigned * length,
		 Dwarf_Unsigned * abbr_count, Dwarf_Error * error)
{
    Dwarf_Small *abbrev_ptr;
    Dwarf_Small *abbrev_section_end;
    Dwarf_Half attr;
    Dwarf_Half attr_form;
    Dwarf_Abbrev ret_abbrev;
    Dwarf_Unsigned labbr_count = 0;
    Dwarf_Unsigned utmp;


    if (dbg == NULL) {
	_dwarf_error(NULL, error, DW_DLE_DBG_NULL);
	return (DW_DLV_ERROR);
    }
    if (dbg->de_debug_abbrev == 0) {
	/* Loads abbrev section (and .debug_info as we do those
	   together). */
	int res = _dwarf_load_debug_info(dbg, error);

	if (res != DW_DLV_OK) {
	    return res;
	}
    }

    if (offset >= dbg->de_debug_abbrev_size) {
	return (DW_DLV_NO_ENTRY);
    }


    ret_abbrev = (Dwarf_Abbrev) _dwarf_get_alloc(dbg, DW_DLA_ABBREV, 1);
    if (ret_abbrev == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }
    ret_abbrev->ab_dbg = dbg;
    if (returned_abbrev == 0 || abbr_count == 0) {
	dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV);
	_dwarf_error(dbg, error, DW_DLE_DWARF_ABBREV_NULL);
	return (DW_DLV_ERROR);
    }


    *abbr_count = 0;
    if (length != NULL)
	*length = 1;

    abbrev_ptr = dbg->de_debug_abbrev + offset;
    abbrev_section_end =
	dbg->de_debug_abbrev + dbg->de_debug_abbrev_size;

    DECODE_LEB128_UWORD(abbrev_ptr, utmp);
    ret_abbrev->ab_code = (Dwarf_Word) utmp;
    if (ret_abbrev->ab_code == 0) {
	*returned_abbrev = ret_abbrev;
	*abbr_count = 0;
	if (length) {
	    *length = 1;
	}
	return (DW_DLV_OK);
    }

    DECODE_LEB128_UWORD(abbrev_ptr, utmp);
    ret_abbrev->ab_tag = utmp;
    ret_abbrev->ab_has_child = *(abbrev_ptr++);
    ret_abbrev->ab_abbrev_ptr = abbrev_ptr;

    do {
	Dwarf_Unsigned utmp2;

	DECODE_LEB128_UWORD(abbrev_ptr, utmp2)
	    attr = (Dwarf_Half) utmp2;
	DECODE_LEB128_UWORD(abbrev_ptr, utmp2)
	    attr_form = (Dwarf_Half) utmp2;

	if (attr != 0)
	    (labbr_count)++;

    } while (abbrev_ptr < abbrev_section_end &&
	     (attr != 0 || attr_form != 0));

    if (abbrev_ptr > abbrev_section_end) {
	dwarf_dealloc(dbg, ret_abbrev, DW_DLA_ABBREV);
	_dwarf_error(dbg, error, DW_DLE_ABBREV_DECODE_ERROR);
	return (DW_DLV_ERROR);
    }

    if (length != NULL)
	*length = abbrev_ptr - dbg->de_debug_abbrev - offset;

    *returned_abbrev = ret_abbrev;
    *abbr_count = labbr_count;
    return (DW_DLV_OK);
}
예제 #9
0
/*
    This function returns a pointer to a Dwarf_Abbrev_List_s
    struct for the abbrev with the given code.  It puts the
    struct on the appropriate hash table.  It also adds all
    the abbrev between the last abbrev added and this one to
    the hash table.  In other words, the .debug_abbrev section
    is scanned sequentially from the top for an abbrev with
    the given code.  All intervening abbrevs are also put 
    into the hash table.

    This function hashes the given code, and checks the chain
    at that hash table entry to see if a Dwarf_Abbrev_List_s
    with the given code exists.  If yes, it returns a pointer
    to that struct.  Otherwise, it scans the .debug_abbrev
    section from the last byte scanned for that CU till either
    an abbrev with the given code is found, or an abbrev code
    of 0 is read.  It puts Dwarf_Abbrev_List_s entries for all
    abbrev's read till that point into the hash table.  The
    hash table contains both a head pointer and a tail pointer
    for each entry.

    While the lists can move and entries can be moved between
    lists on reallocation, any given Dwarf_Abbrev_list entry
    never moves once allocated, so the pointer is safe to return.

    Returns NULL on error.
*/
Dwarf_Abbrev_List
_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Unsigned code)
{
    Dwarf_Debug dbg = cu_context->cc_dbg;
    Dwarf_Hash_Table hash_table_base = cu_context->cc_abbrev_hash_table;
    Dwarf_Hash_Table_Entry entry_base = 0; 
    Dwarf_Hash_Table_Entry entry_cur = 0; 
    Dwarf_Word hash_num = 0;
    Dwarf_Unsigned abbrev_code = 0; 
    Dwarf_Unsigned abbrev_tag  = 0;
    Dwarf_Unsigned attr_name = 0;
    Dwarf_Unsigned attr_form = 0;

    Dwarf_Abbrev_List hash_abbrev_entry = 0;

    Dwarf_Abbrev_List inner_list_entry = 0; 
    Dwarf_Hash_Table_Entry inner_hash_entry = 0; 

    Dwarf_Byte_Ptr abbrev_ptr = 0;
    unsigned hashable_val;

    if ( !hash_table_base->tb_entries ) {
         hash_table_base->tb_table_entry_count =  HT_MULTIPLE;
         hash_table_base->tb_total_abbrev_count= 0;
         hash_table_base->tb_entries =  _dwarf_get_alloc(dbg,
            DW_DLA_HASH_TABLE_ENTRY, 
            hash_table_base->tb_table_entry_count);
         if(! hash_table_base->tb_entries) {
             return NULL;
         }

    } else if (hash_table_base->tb_total_abbrev_count >
          ( hash_table_base->tb_table_entry_count * HT_MULTIPLE) ) {
        struct Dwarf_Hash_Table_s newht;
        /* Effectively multiplies by >= HT_MULTIPLE */
        newht.tb_table_entry_count =  hash_table_base->tb_total_abbrev_count;
        newht.tb_total_abbrev_count = 0;
        newht.tb_entries =  _dwarf_get_alloc(dbg,
            DW_DLA_HASH_TABLE_ENTRY, 
            newht.tb_table_entry_count);

        if(! newht.tb_entries) {
             return NULL;
        }
        /* Copy the existing entries to the new table,
           rehashing each. 
        */
        copy_abbrev_table_to_new_table(hash_table_base, &newht);
        /* Dealloc only the entries hash table array, not the lists
           of things pointed to by a hash table entry array. */
        dwarf_dealloc(dbg, hash_table_base->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
        hash_table_base->tb_entries = 0;
        /* Now overwrite the existing table descriptor with
           the new, newly valid, contents. */
        *hash_table_base = newht;
    } /* Else is ok as is, add entry */ 

    
    hashable_val = code;
    hash_num = hashable_val % 
        hash_table_base->tb_table_entry_count;
    entry_base = hash_table_base->tb_entries;
    entry_cur  = entry_base + hash_num;
   
    /* Determine if the 'code' is the list of synonyms already. */
    for (hash_abbrev_entry = entry_cur->at_head;
         hash_abbrev_entry != NULL && hash_abbrev_entry->ab_code != code;
         hash_abbrev_entry = hash_abbrev_entry->ab_next);
    if (hash_abbrev_entry != NULL) {
        /* This returns a pointer to an abbrev list entry, not 
           the list itself. */
        return (hash_abbrev_entry);
    }

    abbrev_ptr = cu_context->cc_last_abbrev_ptr != NULL ?
        cu_context->cc_last_abbrev_ptr :
        dbg->de_debug_abbrev.dss_data + cu_context->cc_abbrev_offset;

    /* End of abbrev's for this cu, since abbrev code is 0. */
    if (*abbrev_ptr == 0) {
        return (NULL);
    }

    do {
        unsigned new_hashable_val;
        DECODE_LEB128_UWORD(abbrev_ptr, abbrev_code);
        DECODE_LEB128_UWORD(abbrev_ptr, abbrev_tag);

        inner_list_entry = (Dwarf_Abbrev_List)
            _dwarf_get_alloc(cu_context->cc_dbg, DW_DLA_ABBREV_LIST, 1);
        if (inner_list_entry == NULL)
            return (NULL);

        new_hashable_val = abbrev_code;
        hash_num = new_hashable_val % 
            hash_table_base->tb_table_entry_count;
        inner_hash_entry = entry_base + hash_num;
        /* Move_entry_to_new_hash */
        inner_list_entry->ab_next = inner_hash_entry->at_head;
        inner_hash_entry->at_head = inner_list_entry;

        hash_table_base->tb_total_abbrev_count++;

        inner_list_entry->ab_code = abbrev_code;
        inner_list_entry->ab_tag = abbrev_tag;
        inner_list_entry->ab_has_child = *(abbrev_ptr++);
        inner_list_entry->ab_abbrev_ptr = abbrev_ptr;

        /* Cycle thru the abbrev content, ignoring the content except
           to find the end of the content. */
        do {
            DECODE_LEB128_UWORD(abbrev_ptr, attr_name);
            DECODE_LEB128_UWORD(abbrev_ptr, attr_form);
        } while (attr_name != 0 && attr_form != 0);

    } while (*abbrev_ptr != 0 && abbrev_code != code);

    cu_context->cc_last_abbrev_ptr = abbrev_ptr;
    return (abbrev_code == code ? inner_list_entry : NULL);
}
예제 #10
0
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;
    Dwarf_Small *dataptr = 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. */
    dataptr = cu_context->cc_is_info? dbg->de_debug_info.dss_data:
        dbg->de_debug_types.dss_data;

    if (attr->ar_debug_ptr + length >=
        dataptr + 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 - dataptr;


    *return_block = ret_block;
    return (DW_DLV_OK);
}
예제 #11
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;
}
예제 #12
0
/* Internal function, not called by consumer code.
   'prefix' has accumulated the info up thru the cie-id
   and now we consume the rest and build a Dwarf_Cie_s structure.
*/
int
dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
				  struct cie_fde_prefix_s *prefix,
				  Dwarf_Small * frame_ptr,
				  Dwarf_Unsigned cie_count,
				  int use_gnu_cie_calc,
				  Dwarf_Cie * cie_ptr_out,
				  Dwarf_Error * error)
{
    Dwarf_Cie new_cie = 0;

    /* egcs-1.1.2 .eh_frame uses 0 as the distinguishing id. sgi uses
       -1 (in .debug_frame). .eh_frame not quite identical to
       .debug_frame */
    Dwarf_Small eh_fde_encoding = 0;
    Dwarf_Small *augmentation = 0;
    Dwarf_Sword data_alignment_factor = -1;
    Dwarf_Word code_alignment_factor = 4;
    Dwarf_Unsigned return_address_register = 31;
    int local_length_size = 0;
    Dwarf_Word leb128_length = 0;
    Dwarf_Unsigned cie_aug_data_len = 0;
    Dwarf_Small *cie_aug_data = 0;
    Dwarf_Addr gnu_personality_handler_addr = 0;
    unsigned char gnu_personality_handler_encoding = 0;
    unsigned char gnu_lsda_encoding = 0;
    unsigned char gnu_fde_begin_encoding = 0;


    enum Dwarf_augmentation_type augt = aug_unknown;


    /* this is a CIE, Common Information Entry: See the dwarf spec,
       section 6.4.1 */
    Dwarf_Small version = *(Dwarf_Small *) frame_ptr;

    frame_ptr++;
    if (version != DW_CIE_VERSION && version != DW_CIE_VERSION3 && version != DW_CIE_VERSION4) {
	_dwarf_error(dbg, error, DW_DLE_FRAME_VERSION_BAD);
	return (DW_DLV_ERROR);
    }

    augmentation = frame_ptr;
    frame_ptr = frame_ptr + strlen((char *) frame_ptr) + 1;
    augt = _dwarf_get_augmentation_type(dbg,
					augmentation, use_gnu_cie_calc);
    if (augt == aug_eh) {
	/* REFERENCED *//* Not used in this instance */
	Dwarf_Unsigned exception_table_addr;

	/* this is per egcs-1.1.2 as on RH 6.0 */
	READ_UNALIGNED(dbg, exception_table_addr,
		       Dwarf_Unsigned, frame_ptr, local_length_size);
	frame_ptr += local_length_size;
    }
    {
	Dwarf_Unsigned lreg = 0;
	unsigned long size = 0;

	DECODE_LEB128_UWORD(frame_ptr, lreg);
	code_alignment_factor = (Dwarf_Word) lreg;

	data_alignment_factor =
	    (Dwarf_Sword) _dwarf_decode_s_leb128(frame_ptr,
						 &leb128_length);

	frame_ptr = frame_ptr + leb128_length;

	return_address_register =
	    _dwarf_get_return_address_reg(frame_ptr, version, &size);
	if (return_address_register > DW_FRAME_LAST_REG_NUM) {
	    _dwarf_error(dbg, error, DW_DLE_CIE_RET_ADDR_REG_ERROR);
	    return (DW_DLV_ERROR);
	}
	frame_ptr += size;
    }
    switch (augt) {
    case aug_empty_string:
	break;
    case aug_irix_mti_v1:
	break;
    case aug_irix_exception_table:{
	    Dwarf_Unsigned lreg = 0;
	    Dwarf_Word length_of_augmented_fields;

	    /* Decode the length of augmented fields. */
	    DECODE_LEB128_UWORD(frame_ptr, lreg);
	    length_of_augmented_fields = (Dwarf_Word) lreg;


	    /* set the frame_ptr to point at the instruction start. */
	    frame_ptr += length_of_augmented_fields;
	}
	break;

    case aug_eh:{

	    int err = 0;
	    unsigned long increment = 0;

	    if (!use_gnu_cie_calc) {
		/* This should be impossible. */
		_dwarf_error(dbg, error,
			     DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
		return DW_DLV_ERROR;
	    }

	    err = get_gcc_eh_augmentation(dbg, frame_ptr, &increment,
					  augt,
					  prefix->cf_section_ptr,
					  &eh_fde_encoding,
					  (char *) augmentation);
	    if (err == DW_DLV_ERROR) {
		_dwarf_error(dbg, error,
			     DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
		return DW_DLV_ERROR;
	    }
	    frame_ptr += increment;
	    break;
	}
    case aug_gcc_eh_z:{
	    /* Here we have Augmentation Data Length (uleb128) followed 
	       by Augmentation Data bytes. */
	    int res;
	    Dwarf_Unsigned adlen = 0;

	    DECODE_LEB128_UWORD(frame_ptr, adlen);
	    cie_aug_data_len = adlen;
	    cie_aug_data = frame_ptr;
	    res = gnu_aug_encodings(dbg,
				    (char *) augmentation,
				    cie_aug_data,
				    cie_aug_data_len,
				    &gnu_personality_handler_encoding,
				    &gnu_lsda_encoding,
				    &gnu_fde_begin_encoding,
				    &gnu_personality_handler_addr);
	    if (res != DW_DLV_OK) {
		_dwarf_error(dbg, error,
			     DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
		return res;
	    }


	    frame_ptr += adlen;
	    break;
	}
    default:{
	    /* We do not understand the augmentation string. No
	       assumption can be made about any fields other than what
	       we have already read. */
	    frame_ptr = prefix->cf_start_addr +
		prefix->cf_length + prefix->cf_local_length_size
		+ prefix->cf_local_extension_size;
	    /* FIX -- What are the values of data_alignment_factor,
	       code_alignement_factor, return_address_register and
	       instruction start? They were clearly uninitalized in the 
	       previous version and I am leaving them the same way. */
	    break;
	}
    }				/* End switch on augmentation type. */

    new_cie = (Dwarf_Cie) _dwarf_get_alloc(dbg, DW_DLA_CIE, 1);
    if (new_cie == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    new_cie->ci_cie_version_number = version;
    new_cie->ci_initial_table = NULL;
    new_cie->ci_length = (Dwarf_Word) prefix->cf_length;
    new_cie->ci_length_size = prefix->cf_local_length_size;
    new_cie->ci_extension_size = prefix->cf_local_extension_size;
    new_cie->ci_augmentation = (char *) augmentation;

    new_cie->ci_data_alignment_factor =
	(Dwarf_Sbyte) data_alignment_factor;
    new_cie->ci_code_alignment_factor =
	(Dwarf_Small) code_alignment_factor;
    new_cie->ci_return_address_register = return_address_register;
    new_cie->ci_cie_start = prefix->cf_start_addr;
    new_cie->ci_cie_instr_start = frame_ptr;
    new_cie->ci_dbg = dbg;
    new_cie->ci_augmentation_type = augt;
    new_cie->ci_gnu_eh_augmentation_len = cie_aug_data_len;
    new_cie->ci_gnu_eh_augmentation_bytes = cie_aug_data;
    new_cie->ci_gnu_personality_handler_encoding =
	gnu_personality_handler_encoding;
    new_cie->ci_gnu_personality_handler_addr =
	gnu_personality_handler_addr;
    new_cie->ci_gnu_lsda_encoding = gnu_lsda_encoding;
    new_cie->ci_gnu_fde_begin_encoding = gnu_fde_begin_encoding;

    new_cie->ci_index = cie_count;
    new_cie->ci_section_ptr = prefix->cf_section_ptr;

    *cie_ptr_out = new_cie;
    return DW_DLV_OK;

}
예제 #13
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);
}
예제 #14
0
int dwarf_get_ranges_a(Dwarf_Debug dbg,
    Dwarf_Off rangesoffset,
    Dwarf_Die die,
    Dwarf_Ranges ** rangesbuf,
    Dwarf_Signed * listlen,
    Dwarf_Unsigned * bytecount,
    Dwarf_Error * error)
{
    Dwarf_Small *rangeptr = 0;
    Dwarf_Small *beginrangeptr = 0;
    Dwarf_Small *section_end = 0;
    unsigned entry_count = 0;
    struct ranges_entry *base = 0;
    struct ranges_entry *last = 0;
    struct ranges_entry *curre = 0;
    Dwarf_Ranges * ranges_data_out = 0;
    unsigned copyindex = 0;
    Dwarf_Half address_size = 0;
    int res = DW_DLV_ERROR;
    Dwarf_Unsigned rangebase = 0;
    Dwarf_Debug localdbg = dbg;
    Dwarf_Error localerror = 0;

    if (die &&localdbg->de_tied_data.td_tied_object) {
        /*  ASSERT: localdbg->de_debug_ranges is missing: DW_DLV_NO_ENTRY.
            So lets not look in dbg. */
        Dwarf_CU_Context context = 0;
        int restied = 0;

        context = die->di_cu_context;
        restied = _dwarf_get_ranges_base_attr_from_tied(localdbg,
            context,
            &rangebase,
            error);
        if (restied == DW_DLV_ERROR ) {
            if(!error) {
                return restied;
            }
            dwarf_dealloc(localdbg,*error,DW_DLA_ERROR);
            *error = 0;
            /* Nothing else to do. Look in original dbg. */
        } else if (restied == DW_DLV_NO_ENTRY ) {
            /* Nothing else to do. Look in original dbg. */
        } else {
            /*  Ranges are never in a split dwarf object.
                In the base object
                instead. Use the tied_object */
            localdbg = dbg->de_tied_data.td_tied_object;
        }
    }


    res = _dwarf_load_section(localdbg, &localdbg->de_debug_ranges,&localerror);
    if (res == DW_DLV_ERROR) {
        _dwarf_error_mv_s_to_t(localdbg,&localerror,dbg,error);
        return res;
    } else if (res == DW_DLV_NO_ENTRY) {
        return res;
    }

    if ((rangesoffset +rangebase) >= localdbg->de_debug_ranges.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
        return (DW_DLV_ERROR);

    }
    address_size = _dwarf_get_address_size(localdbg, die);
    section_end = localdbg->de_debug_ranges.dss_data +
        localdbg->de_debug_ranges.dss_size;
    rangeptr = localdbg->de_debug_ranges.dss_data + rangesoffset+rangebase;
    beginrangeptr = rangeptr;

    for (;;) {
        struct ranges_entry * re = 0;

        if (rangeptr == section_end) {
            break;
        }
        if (rangeptr  > section_end) {
            free_allocated_ranges(base);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
            return (DW_DLV_ERROR);
            break;
        }
        re = calloc(sizeof(struct ranges_entry),1);
        if (!re) {
            free_allocated_ranges(base);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
            return (DW_DLV_ERROR);
        }
        if ((rangeptr + (2*address_size)) > section_end) {
            free(re);
            free_allocated_ranges(base);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OFFSET_BAD);
            return (DW_DLV_ERROR);
        }
        entry_count++;
        res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr1,
            rangeptr, address_size,error,section_end);
        if (res != DW_DLV_OK) {
            free(re);
            free_allocated_ranges(base);
            return res;
        }
        rangeptr +=  address_size;
        res = read_unaligned_addr_check(localdbg,&re->cur.dwr_addr2,
            rangeptr, address_size,error,section_end);
        if (res != DW_DLV_OK) {
            free(re);
            free_allocated_ranges(base);
            return res;
        }
        rangeptr +=  address_size;
        if (!base) {
            base = re;
            last = re;
        } else {
            last->next = re;
            last = re;
        }
        if (re->cur.dwr_addr1 == 0 && re->cur.dwr_addr2 == 0) {
            re->cur.dwr_type =  DW_RANGES_END;
            break;
        } else if (re->cur.dwr_addr1 == MAX_ADDR) {
            re->cur.dwr_type =  DW_RANGES_ADDRESS_SELECTION;
        } else {
            re->cur.dwr_type =  DW_RANGES_ENTRY;
        }
    }

    /* We return ranges on dbg, so use that to allocate. */
    ranges_data_out =   (Dwarf_Ranges *)
        _dwarf_get_alloc(dbg,DW_DLA_RANGES,entry_count);
    if (!ranges_data_out) {
        /* Error, apply to original, not local dbg. */
        free_allocated_ranges(base);
        _dwarf_error(dbg, error, DW_DLE_DEBUG_RANGES_OUT_OF_MEM);
        return (DW_DLV_ERROR);
    }
    curre = base;
    *rangesbuf = ranges_data_out;
    *listlen = entry_count;
    for (copyindex = 0; curre && (copyindex < entry_count);
        ++copyindex,++ranges_data_out) {

        *ranges_data_out = curre->cur;
        curre = curre->next;
    }
    /* ASSERT: curre == NULL */
    free_allocated_ranges(base);
    base = 0;
    /* Callers will often not care about the bytes used. */
    if (bytecount) {
        *bytecount = rangeptr - beginrangeptr;
    }
    return DW_DLV_OK;
}
예제 #15
0
/*
    Given a Dwarf_Block that represents a location expression,
    this function returns a pointer to a Dwarf_Locdesc struct 
    that has its ld_cents field set to the number of location 
    operators in the block, and its ld_s field pointing to a 
    contiguous block of Dwarf_Loc structs.  However, the 
    ld_lopc and ld_hipc values are uninitialized.  Returns 
    NULL on error.  This function assumes that the length of 
    the block is greater than 0.  Zero length location expressions 
    to represent variables that have been optimized away are 
    handled in the calling function.
*/
static Dwarf_Locdesc *
_dwarf_get_locdesc(Dwarf_Debug dbg,
    Dwarf_Block * loc_block,
    Dwarf_Half address_size,
    Dwarf_Addr lowpc,
    Dwarf_Addr highpc, 
    Dwarf_Error * error)
{
    /* Size of the block containing the location expression. */
    Dwarf_Unsigned loc_len = 0;

    /* Sweeps the block containing the location expression. */
    Dwarf_Small *loc_ptr = 0;

    /* Current location operator. */
    Dwarf_Small atom = 0;

    /* Offset of current operator from start of block. */
    Dwarf_Unsigned offset = 0;

    /* Operands of current location operator. */
    Dwarf_Unsigned operand1, operand2;

    /* Used to chain the Dwarf_Loc_Chain_s structs. */
    Dwarf_Loc_Chain curr_loc = NULL;
    Dwarf_Loc_Chain prev_loc = NULL;
    Dwarf_Loc_Chain head_loc = NULL;

    /* Count of the number of location operators. */
    Dwarf_Unsigned op_count = 0;

    /* Contiguous block of Dwarf_Loc's for Dwarf_Locdesc. */
    Dwarf_Loc *block_loc = 0;

    /* Dwarf_Locdesc pointer to be returned. */
    Dwarf_Locdesc *locdesc = 0;

    Dwarf_Word leb128_length = 0;
    Dwarf_Unsigned i = 0;

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

    loc_len = loc_block->bl_len;
    loc_ptr = loc_block->bl_data;

    offset = 0;
    op_count = 0;
    while (offset < loc_len) {

        operand1 = 0;
        operand2 = 0;
        op_count++;

        atom = *(Dwarf_Small *) loc_ptr;
        loc_ptr++;
        offset++;

        curr_loc =
            (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN,
                                               1);
        if (curr_loc == NULL) {
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return (NULL);
        }
        curr_loc->lc_offset = offset;
        curr_loc->lc_atom = atom;
        switch (atom) {

        case DW_OP_reg0:
        case DW_OP_reg1:
        case DW_OP_reg2:
        case DW_OP_reg3:
        case DW_OP_reg4:
        case DW_OP_reg5:
        case DW_OP_reg6:
        case DW_OP_reg7:
        case DW_OP_reg8:
        case DW_OP_reg9:
        case DW_OP_reg10:
        case DW_OP_reg11:
        case DW_OP_reg12:
        case DW_OP_reg13:
        case DW_OP_reg14:
        case DW_OP_reg15:
        case DW_OP_reg16:
        case DW_OP_reg17:
        case DW_OP_reg18:
        case DW_OP_reg19:
        case DW_OP_reg20:
        case DW_OP_reg21:
        case DW_OP_reg22:
        case DW_OP_reg23:
        case DW_OP_reg24:
        case DW_OP_reg25:
        case DW_OP_reg26:
        case DW_OP_reg27:
        case DW_OP_reg28:
        case DW_OP_reg29:
        case DW_OP_reg30:
        case DW_OP_reg31:
            break;

        case DW_OP_regx:
            operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_lit0:
        case DW_OP_lit1:
        case DW_OP_lit2:
        case DW_OP_lit3:
        case DW_OP_lit4:
        case DW_OP_lit5:
        case DW_OP_lit6:
        case DW_OP_lit7:
        case DW_OP_lit8:
        case DW_OP_lit9:
        case DW_OP_lit10:
        case DW_OP_lit11:
        case DW_OP_lit12:
        case DW_OP_lit13:
        case DW_OP_lit14:
        case DW_OP_lit15:
        case DW_OP_lit16:
        case DW_OP_lit17:
        case DW_OP_lit18:
        case DW_OP_lit19:
        case DW_OP_lit20:
        case DW_OP_lit21:
        case DW_OP_lit22:
        case DW_OP_lit23:
        case DW_OP_lit24:
        case DW_OP_lit25:
        case DW_OP_lit26:
        case DW_OP_lit27:
        case DW_OP_lit28:
        case DW_OP_lit29:
        case DW_OP_lit30:
        case DW_OP_lit31:
            operand1 = atom - DW_OP_lit0;
            break;

        case DW_OP_addr:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned,
                           loc_ptr, address_size);
            loc_ptr += address_size;
            offset += address_size;
            break;

        case DW_OP_const1u:
            operand1 = *(Dwarf_Small *) loc_ptr;
            loc_ptr = loc_ptr + 1;
            offset = offset + 1;
            break;

        case DW_OP_const1s:
            operand1 = *(Dwarf_Sbyte *) loc_ptr;
            SIGN_EXTEND(operand1,1);
            loc_ptr = loc_ptr + 1;
            offset = offset + 1;
            break;

        case DW_OP_const2u:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
            loc_ptr = loc_ptr + 2;
            offset = offset + 2;
            break;

        case DW_OP_const2s:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
            SIGN_EXTEND(operand1,2);
            loc_ptr = loc_ptr + 2;
            offset = offset + 2;
            break;

        case DW_OP_const4u:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
            loc_ptr = loc_ptr + 4;
            offset = offset + 4;
            break;

        case DW_OP_const4s:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
            SIGN_EXTEND(operand1,4);
            loc_ptr = loc_ptr + 4;
            offset = offset + 4;
            break;

        case DW_OP_const8u:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
            loc_ptr = loc_ptr + 8;
            offset = offset + 8;
            break;

        case DW_OP_const8s:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 8);
            loc_ptr = loc_ptr + 8;
            offset = offset + 8;
            break;

        case DW_OP_constu:
            operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_consts:
            operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_fbreg:
            operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_breg0:
        case DW_OP_breg1:
        case DW_OP_breg2:
        case DW_OP_breg3:
        case DW_OP_breg4:
        case DW_OP_breg5:
        case DW_OP_breg6:
        case DW_OP_breg7:
        case DW_OP_breg8:
        case DW_OP_breg9:
        case DW_OP_breg10:
        case DW_OP_breg11:
        case DW_OP_breg12:
        case DW_OP_breg13:
        case DW_OP_breg14:
        case DW_OP_breg15:
        case DW_OP_breg16:
        case DW_OP_breg17:
        case DW_OP_breg18:
        case DW_OP_breg19:
        case DW_OP_breg20:
        case DW_OP_breg21:
        case DW_OP_breg22:
        case DW_OP_breg23:
        case DW_OP_breg24:
        case DW_OP_breg25:
        case DW_OP_breg26:
        case DW_OP_breg27:
        case DW_OP_breg28:
        case DW_OP_breg29:
        case DW_OP_breg30:
        case DW_OP_breg31:
            operand1 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_bregx:
            /* uleb reg num followed by sleb offset */
            operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;

            operand2 = _dwarf_decode_s_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_dup:
        case DW_OP_drop:
            break;

        case DW_OP_pick:
            operand1 = *(Dwarf_Small *) loc_ptr;
            loc_ptr = loc_ptr + 1;
            offset = offset + 1;
            break;

        case DW_OP_over:
        case DW_OP_swap:
        case DW_OP_rot:
        case DW_OP_deref:
            break;

        case DW_OP_deref_size:
            operand1 = *(Dwarf_Small *) loc_ptr;
            loc_ptr = loc_ptr + 1;
            offset = offset + 1;
            break;

        case DW_OP_xderef:
            break;

        case DW_OP_xderef_size:
            operand1 = *(Dwarf_Small *) loc_ptr;
            loc_ptr = loc_ptr + 1;
            offset = offset + 1;
            break;

        case DW_OP_abs:
        case DW_OP_and:
        case DW_OP_div:
        case DW_OP_minus:
        case DW_OP_mod:
        case DW_OP_mul:
        case DW_OP_neg:
        case DW_OP_not:
        case DW_OP_or:
        case DW_OP_plus:
            break;

        case DW_OP_plus_uconst:
            operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_shl:
        case DW_OP_shr:
        case DW_OP_shra:
        case DW_OP_xor:
            break;

        case DW_OP_le:
        case DW_OP_ge:
        case DW_OP_eq:
        case DW_OP_lt:
        case DW_OP_gt:
        case DW_OP_ne:
            break;

        case DW_OP_skip:
        case DW_OP_bra:
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
            loc_ptr = loc_ptr + 2;
            offset = offset + 2;
            break;

        case DW_OP_piece:
            operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;

        case DW_OP_nop:
            break;
        case DW_OP_push_object_address: /* DWARF3 */
            break;
        case DW_OP_call2:       /* DWARF3 */
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 2);
            loc_ptr = loc_ptr + 2;
            offset = offset + 2;
            break;

        case DW_OP_call4:       /* DWARF3 */
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr, 4);
            loc_ptr = loc_ptr + 4;
            offset = offset + 4;
            break;
        case DW_OP_call_ref:    /* DWARF3 */
            READ_UNALIGNED(dbg, operand1, Dwarf_Unsigned, loc_ptr,
                           dbg->de_length_size);
            loc_ptr = loc_ptr + dbg->de_length_size;
            offset = offset + dbg->de_length_size;
            break;

        case DW_OP_form_tls_address:    /* DWARF3f */
            break;
        case DW_OP_call_frame_cfa:      /* DWARF3f */
            break;
        case DW_OP_bit_piece:   /* DWARF3f */
            /* uleb size in bits followed by uleb offset in bits */
            operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;

            operand2 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;
            break;
        case DW_OP_implicit_value: /* DWARF4 */
            /* uleb length of value bytes followed by that
               number of bytes of the value. */
            operand1 = _dwarf_decode_u_leb128(loc_ptr, &leb128_length);
            loc_ptr = loc_ptr + leb128_length;
            offset = offset + leb128_length;

            /* Second operand is block of 'operand1' bytes of stuff. */
            /* This using the second operand as a pointer
               is quite ugly. */
            /* This gets an ugly compiler warning. Sorry. */
            operand2 = (Dwarf_Unsigned)(uintptr_t)loc_ptr; 
            offset = offset + operand1;
            loc_ptr = loc_ptr + operand1;
            break;
        case DW_OP_stack_value:  /* DWARF4 */
            break;


        default:
            _dwarf_error(dbg, error, DW_DLE_LOC_EXPR_BAD);
            return (NULL);
        }


        curr_loc->lc_number = operand1;
        curr_loc->lc_number2 = operand2;

        if (head_loc == NULL)
            head_loc = prev_loc = curr_loc;
        else {
            prev_loc->lc_next = curr_loc;
            prev_loc = curr_loc;
        }
    }

    block_loc =
        (Dwarf_Loc *) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK, op_count);
    if (block_loc == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (NULL);
    }

    curr_loc = head_loc;
    for (i = 0; i < op_count; i++) {
        (block_loc + i)->lr_atom = curr_loc->lc_atom;
        (block_loc + i)->lr_number = curr_loc->lc_number;
        (block_loc + i)->lr_number2 = curr_loc->lc_number2;
        (block_loc + i)->lr_offset = curr_loc->lc_offset;

        prev_loc = curr_loc;
        curr_loc = curr_loc->lc_next;
        dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
    }

    locdesc =
        (Dwarf_Locdesc *) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC, 1);
    if (locdesc == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (NULL);
    }

    locdesc->ld_cents = op_count;
    locdesc->ld_s = block_loc;
    locdesc->ld_from_loclist = loc_block->bl_from_loclist;
    locdesc->ld_section_offset = loc_block->bl_section_offset;
    locdesc->ld_lopc = lowpc;
    locdesc->ld_hipc = highpc;

    return (locdesc);
}
예제 #16
0
/*  return DW_DLV_OK if ok. else DW_DLV_NO_ENTRY or DW_DLV_ERROR
    If err_count_out is non-NULL, this is a special 'check'
    call.  */
static int
_dwarf_internal_printlines(Dwarf_Die die,
    Dwarf_Error * error,
    int * err_count_out,
    int only_line_header)
{
    /*  This pointer is used to scan the portion of the .debug_line
        section for the current cu. */
    Dwarf_Small *line_ptr = 0;
    Dwarf_Small *orig_line_ptr = 0;

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

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

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

    Dwarf_Sword i=0;
    Dwarf_Word u=0;

    /*  These variables are used to decode leb128 numbers. Leb128_num
        holds the decoded number, and leb128_length is its length in
        bytes. */
    Dwarf_Half attrform = 0;

    /*  In case there are wierd bytes 'after' the line table
        prologue this lets us print something. This is a gcc
        compiler bug and we expect the bytes count to be 12.  */
    Dwarf_Small* bogus_bytes_ptr = 0;
    Dwarf_Unsigned bogus_bytes_count = 0;
    Dwarf_Half address_size = 0;
    Dwarf_Unsigned fission_offset = 0;


    /* The Dwarf_Debug this die belongs to. */
    Dwarf_Debug dbg=0;
    Dwarf_CU_Context cu_context = 0;
    Dwarf_Line_Context line_context = 0;
    int resattr = DW_DLV_ERROR;
    int lres =    DW_DLV_ERROR;
    int res  =    DW_DLV_ERROR;
    Dwarf_Small *line_ptr_actuals  = 0;
    Dwarf_Small *line_ptr_end = 0;
    Dwarf_Small *section_start = 0;

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

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

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

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

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


    /*  The list of relevant FORMs is small.
        DW_FORM_data4, DW_FORM_data8, DW_FORM_sec_offset
    */
    lres = dwarf_whatform(stmt_list_attr,&attrform,error);
    if (lres != DW_DLV_OK) {
        return lres;
    }
    if (attrform != DW_FORM_data4 && attrform != DW_FORM_data8 &&
        attrform != DW_FORM_sec_offset ) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    lres = dwarf_global_formref(stmt_list_attr, &line_offset, error);
    if (lres != DW_DLV_OK) {
        return lres;
    }

    if (line_offset >= dbg->de_debug_line.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_LINE_OFFSET_BAD);
        return (DW_DLV_ERROR);
    }
    section_start =  dbg->de_debug_line.dss_data;
    {
        Dwarf_Unsigned fission_size = 0;
        int resfis = _dwarf_get_fission_addition_die(die, DW_SECT_LINE,
            &fission_offset,&fission_size,error);
        if(resfis != DW_DLV_OK) {
            return resfis;
        }
    }

    orig_line_ptr = section_start + line_offset + fission_offset;
    line_ptr = orig_line_ptr;
    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 = DW_DLV_ERROR;
        char *cdir = 0;

        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);
    }
    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);
    }
    {
        Dwarf_Small *newlinep = 0;
        int dres = _dwarf_read_line_table_header(dbg,
            cu_context,
            section_start,
            line_ptr,
            dbg->de_debug_line.dss_size,
            &newlinep,
            line_context,
            &bogus_bytes_ptr,
            &bogus_bytes_count,
            error,
            err_count_out);
        if (dres == DW_DLV_ERROR) {
            dwarf_srclines_dealloc_b(line_context);
            return dres;
        }
        if (dres == DW_DLV_NO_ENTRY) {
            dwarf_srclines_dealloc_b(line_context);
            return dres;
        }
        line_ptr_end = line_context->lc_line_ptr_end;
        line_ptr = newlinep;
        if (line_context->lc_actuals_table_offset > 0) {
            line_ptr_actuals = line_context->lc_line_prologue_start +
                line_context->lc_actuals_table_offset;
        }
    }
    line_context->lc_compilation_directory = comp_dir;
    if (only_line_header) {
        /* Just checking for header errors, nothing more here.*/
        dwarf_srclines_dealloc_b(line_context);
        return DW_DLV_OK;
    }

    dwarf_printf(dbg,
        "total line info length %ld bytes,"
        " line offset 0x%" DW_PR_XZEROS DW_PR_DUx
        " %" DW_PR_DUu "\n",
        (long) line_context->lc_total_length,
        line_context->lc_section_offset,
        line_context->lc_section_offset);
    if (line_context->lc_version_number <= DW_LINE_VERSION5) {
        dwarf_printf(dbg,
            "line table version %d\n",(int) line_context->lc_version_number);
    } else {
        dwarf_printf(dbg,
            "line table version 0x%x\n",(int) line_context->lc_version_number);
    }
    dwarf_printf(dbg,
        "line table length field length %d prologue length %d\n",
        (int)line_context->lc_length_field_length,
        (int)line_context->lc_prologue_length);
    dwarf_printf(dbg,
        "compilation_directory %s\n",
        comp_dir ? ((char *) comp_dir) : "");

    dwarf_printf(dbg,
        "  min instruction length %d\n",
        (int) line_context->lc_minimum_instruction_length);
    if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) {
        dwarf_printf(dbg, "  actuals table offset "
            "0x%" DW_PR_XZEROS DW_PR_DUx
            " logicals table offset "
            "0x%" DW_PR_XZEROS DW_PR_DUx "\n",
            line_context->lc_actuals_table_offset,
            line_context->lc_logicals_table_offset);
    }
    if (line_context->lc_version_number == DW_LINE_VERSION5) {
        dwarf_printf(dbg,
            "  segment selector size %d\n",
            (int) line_context->lc_segment_selector_size);
        dwarf_printf(dbg,
            "  address    size       %d\n",
            (int) line_context->lc_address_size);
    }
    dwarf_printf(dbg,
        "  default is stmt        %d\n",(int)line_context->lc_default_is_stmt);
    dwarf_printf(dbg,
        "  line base              %d\n",(int)line_context->lc_line_base);
    dwarf_printf(dbg,
        "  line_range             %d\n",(int)line_context->lc_line_range);
    dwarf_printf(dbg,
        "  opcode base            %d\n",(int)line_context->lc_opcode_base);
    dwarf_printf(dbg,
        "  standard opcode count  %d\n",(int)line_context->lc_std_op_count);

    for (i = 1; i < line_context->lc_opcode_base; i++) {
        dwarf_printf(dbg,
            "  opcode[%2d] length  %d\n", (int) i,
            (int) line_context->lc_opcode_length_table[i - 1]);
    }
    dwarf_printf(dbg,
        "  include directories count %d\n",
        (int) line_context->lc_include_directories_count);
    for (u = 0; u < line_context->lc_include_directories_count; ++u) {
        dwarf_printf(dbg,
            "  include dir[%u] %s\n",
            (int) u, line_context->lc_include_directories[u]);
    }
    dwarf_printf(dbg,
        "  files count            %d\n",
        (int) line_context->lc_file_entry_count);

    if (line_context->lc_file_entry_count) {
        Dwarf_File_Entry fe = line_context->lc_file_entries;
        Dwarf_File_Entry fe2 = fe;
        unsigned fiu = 0;

        for (fiu = 0 ; fe2 ; fe2 = fe->fi_next,++fiu ) {
            Dwarf_Unsigned tlm2 = 0;
            Dwarf_Unsigned di = 0;
            Dwarf_Unsigned fl = 0;

            fe = fe2;
            tlm2 = fe->fi_time_last_mod;
            di = fe->fi_dir_index;
            fl = fe->fi_file_length;

            dwarf_printf(dbg,
                "  file[%u]  %s (file-number: %u) \n",
                (unsigned) fiu, (char *) fe->fi_file_name,
                (unsigned)(fiu+1));
            dwarf_printf(dbg,
                "    dir index %d\n", (int) di);
            {
                time_t tt = (time_t) tlm2;

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

    if (line_context->lc_version_number == EXPERIMENTAL_LINE_TABLES_VERSION) {
        /*  Print the subprograms list. */
        Dwarf_Unsigned count = line_context->lc_subprogs_count;
        Dwarf_Unsigned exu = 0;
        Dwarf_Subprog_Entry sub = line_context->lc_subprogs;
        dwarf_printf(dbg,"  subprograms count"
            " %" DW_PR_DUu "\n",count);
        if (count > 0) {
            dwarf_printf(dbg,"    indx  file   line   name\n");
        }
        for (exu = 0 ; exu < count ; exu++,sub++) {
            dwarf_printf(dbg,"    [%2" DW_PR_DUu "] %4" DW_PR_DUu
                "    %4" DW_PR_DUu " %s\n",
                exu+1,
                sub->ds_decl_file,
                sub->ds_decl_line,
                sub->ds_subprog_name);
        }
    }
    {
        Dwarf_Unsigned offset = 0;
        if (bogus_bytes_count > 0) {
            Dwarf_Unsigned wcount = bogus_bytes_count;
            Dwarf_Unsigned boffset = bogus_bytes_ptr - section_start;
            dwarf_printf(dbg,
                "*** DWARF CHECK: the line table prologue  header_length "
                " is %" DW_PR_DUu " too high, we pretend it is smaller."
                "Section offset: 0x%" DW_PR_XZEROS DW_PR_DUx
                " (%" DW_PR_DUu ") ***\n",
                wcount, boffset,boffset);
            *err_count_out += 1;
        }
        offset = line_ptr - section_start;
        dwarf_printf(dbg,
            "  statement prog offset in section: 0x%"
            DW_PR_XZEROS DW_PR_DUx " (%" DW_PR_DUu ")\n",
            offset, offset);
    }

    {
        Dwarf_Bool doaddrs = false;
        Dwarf_Bool dolines = true;

        _dwarf_print_line_context_record(dbg,line_context);
        if (!line_ptr_actuals) {
            /* Normal single level line table. */

            Dwarf_Bool is_single_table = true;
            Dwarf_Bool is_actuals_table = false;
            print_line_header(dbg, is_single_table, is_actuals_table);
            res = read_line_table_program(dbg,
                line_ptr, line_ptr_end, orig_line_ptr,
                section_start,
                line_context,
                address_size, doaddrs, dolines,
                is_single_table,
                is_actuals_table,
                error,
                err_count_out);
            if (res != DW_DLV_OK) {
                dwarf_srclines_dealloc_b(line_context);
                return res;
            }
        } else {
            Dwarf_Bool is_single_table = false;
            Dwarf_Bool is_actuals_table = false;
            if (line_context->lc_version_number !=
                EXPERIMENTAL_LINE_TABLES_VERSION) {
                dwarf_srclines_dealloc_b(line_context);
                _dwarf_error(dbg, error, DW_DLE_VERSION_STAMP_ERROR);
                return (DW_DLV_ERROR);
            }
            /* Read Logicals */
            print_line_header(dbg, is_single_table, is_actuals_table);
            res = read_line_table_program(dbg,
                line_ptr, line_ptr_actuals, orig_line_ptr,
                section_start,
                line_context,
                address_size, doaddrs, dolines,
                is_single_table,
                is_actuals_table,
                error,err_count_out);
            if (res != DW_DLV_OK) {
                dwarf_srclines_dealloc_b(line_context);
                return res;
            }
            if (line_context->lc_actuals_table_offset > 0) {
                is_actuals_table = true;
                /* Read Actuals */

                print_line_header(dbg, is_single_table, is_actuals_table);
                res = read_line_table_program(dbg,
                    line_ptr_actuals, line_ptr_end, orig_line_ptr,
                    section_start,
                    line_context,
                    address_size, doaddrs, dolines,
                    is_single_table,
                    is_actuals_table,
                    error,
                    err_count_out);
                if (res != DW_DLV_OK) {
                    dwarf_srclines_dealloc_b(line_context);
                    return res;
                }
            }
        }
    }
    dwarf_srclines_dealloc_b(line_context);
    return DW_DLV_OK;
}
예제 #17
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);
}
예제 #18
0
int
dwarf_get_xu_index_header(Dwarf_Debug dbg,
    /* Pass in section_type "tu" or "cu" */
    const char *     section_type,
    Dwarf_Xu_Index_Header * xuptr,
    Dwarf_Unsigned * version,
    Dwarf_Unsigned * number_of_columns, /* L */
    Dwarf_Unsigned * number_of_CUs,     /* N */
    Dwarf_Unsigned * number_of_slots,   /* M */
    const char    ** section_name,
    Dwarf_Error    * error)
{
    Dwarf_Xu_Index_Header indexptr = 0;
    int res = DW_DLV_ERROR;
    struct Dwarf_Section_s *sect = 0;
    Dwarf_Unsigned local_version = 0;
    Dwarf_Unsigned num_col  = 0;
    Dwarf_Unsigned num_CUs  = 0;
    Dwarf_Unsigned num_slots  = 0;
    Dwarf_Small *data = 0;
    Dwarf_Unsigned tables_end_offset = 0;
    Dwarf_Unsigned hash_tab_offset = 0;
    Dwarf_Unsigned indexes_tab_offset = 0;
    Dwarf_Unsigned section_offsets_tab_offset = 0;
    Dwarf_Unsigned section_sizes_tab_offset = 0;
    unsigned datalen32 = LEN32BIT;

    if (!strcmp(section_type,"cu") ) {
        sect = &dbg->de_debug_cu_index;
    } else if (!strcmp(section_type,"tu") ) {
        sect = &dbg->de_debug_tu_index;
    } else {
        _dwarf_error(dbg, error, DW_DLE_XU_TYPE_ARG_ERROR);
        return DW_DLV_ERROR;
    }
    if (!sect->dss_size) {
        return DW_DLV_NO_ENTRY;
    }

    if (!sect->dss_data) {
        res = _dwarf_load_section(dbg, sect,error);
        if (res != DW_DLV_OK) {
            return res;
        }
    }

    data = sect->dss_data;

    if (sect->dss_size < (4*datalen32) ) {
        _dwarf_error(dbg, error, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION);
        return (DW_DLV_ERROR);
    }
    READ_UNALIGNED(dbg,local_version, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    READ_UNALIGNED(dbg,num_col, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    READ_UNALIGNED(dbg,num_CUs, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    READ_UNALIGNED(dbg,num_slots, Dwarf_Unsigned,
        data,datalen32);
    data += datalen32;
    hash_tab_offset = datalen32*4;
    indexes_tab_offset = hash_tab_offset + (num_slots * HASHSIGNATURELEN);
    section_offsets_tab_offset = indexes_tab_offset +
        (num_slots *datalen32);

    section_sizes_tab_offset = section_offsets_tab_offset +
        ((num_CUs +1) *num_col* datalen32) ;
    tables_end_offset = section_sizes_tab_offset +
        ((num_CUs   ) *num_col* datalen32);

    if ( tables_end_offset > sect->dss_size) {
        /* Something is badly wrong here. */
        _dwarf_error(dbg, error, DW_DLE_ERRONEOUS_GDB_INDEX_SECTION);
        return (DW_DLV_ERROR);
    }


    indexptr = _dwarf_get_alloc(dbg,DW_DLA_XU_INDEX,1);
    if (indexptr == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    strcpy(indexptr->gx_type,section_type);
    indexptr->gx_dbg = dbg;
    indexptr->gx_section_length = sect->dss_size;
    indexptr->gx_section_data   = sect->dss_data;
    indexptr->gx_section_name   = sect->dss_name;
    indexptr->gx_version        = local_version;
    indexptr->gx_column_count_sections = num_col;
    indexptr->gx_units_in_index = num_CUs;
    indexptr->gx_slots_in_hash  = num_slots;
    indexptr->gx_hash_table_offset  =  hash_tab_offset;
    indexptr->gx_index_table_offset  = indexes_tab_offset;
    indexptr->gx_section_offsets_offset  = section_offsets_tab_offset;
    indexptr->gx_section_sizes_offset  = section_sizes_tab_offset;

    *xuptr             =     indexptr;
    *version           = indexptr->gx_version;
    *number_of_columns = indexptr->gx_column_count_sections;
    *number_of_CUs     = indexptr->gx_units_in_index;
    *number_of_slots   = indexptr->gx_slots_in_hash;
    *section_name      = indexptr->gx_section_name;
    return DW_DLV_OK;
}
예제 #19
0
/*  Given a Dwarf_Block that represents a location expression,
    this function returns a pointer to a Dwarf_Locdesc struct
    that has its ld_cents field set to the number of location
    operators in the block, and its ld_s field pointing to a
    contiguous block of Dwarf_Loc structs.  However, the
    ld_lopc and ld_hipc values are uninitialized.  Returns
    DW_DLV_ERROR on error.
    This function assumes that the length of
    the block is greater than 0.  Zero length location expressions
    to represent variables that have been optimized away are
    handled in the calling function.

    address_size, offset_size, and version_stamp are
    per-CU, not per-object or per dbg.
    We cannot use dbg directly to get those values.

    Use for DWARF 2,3,4. Not for DWARF5.

*/
static int
_dwarf_get_locdesc(Dwarf_Debug dbg,
    Dwarf_Block_c * loc_block,
    Dwarf_Half address_size,
    Dwarf_Half offset_size,
    Dwarf_Small version_stamp,
    Dwarf_Addr lowpc,
    Dwarf_Addr highpc,
    Dwarf_Locdesc ** locdesc_out,
    Dwarf_Error * error)
{
    /* Offset of current operator from start of block. */
    Dwarf_Unsigned offset = 0;

    /* Used to chain the Dwarf_Loc_Chain_s structs. */
    Dwarf_Loc_Chain new_loc = NULL;
    Dwarf_Loc_Chain prev_loc = NULL;
    Dwarf_Loc_Chain head_loc = NULL;

    /* Count of the number of location operators. */
    Dwarf_Unsigned op_count = 0;

    /* Contiguous block of Dwarf_Loc's for Dwarf_Locdesc. */
    Dwarf_Loc *block_loc = 0;

    /* Dwarf_Locdesc pointer to be returned. */
    Dwarf_Locdesc *locdesc = 0;

    Dwarf_Unsigned i = 0;
    int res = 0;

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

    offset = 0;
    op_count = 0;


    res = _dwarf_loc_block_sanity_check(dbg,loc_block,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    /* OLD loop getting Loc operators. No DWARF5 */
    while (offset <= loc_block->bl_len) {
        Dwarf_Unsigned nextoffset = 0;
        struct Dwarf_Loc_c_s temp_loc;

        res = _dwarf_read_loc_expr_op(dbg,loc_block,
            op_count,
            version_stamp,
            offset_size,
            address_size,
            offset,
            &nextoffset,
            &temp_loc,
            error);
        if (res == DW_DLV_ERROR) {
            return res;
        }
        if (res == DW_DLV_NO_ENTRY) {
            /* Normal end. */
            break;
        }
        op_count++;
        new_loc =
            (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN, 1);
        if (new_loc == NULL) {
            /*  Some memory may leak here.  */
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return DW_DLV_ERROR;
        }

        /* Copying only the fields needed by DWARF 2,3,4 */
        new_loc->lc_atom    = temp_loc.lr_atom;
        new_loc->lc_opnumber= temp_loc.lr_opnumber;
        new_loc->lc_number  = temp_loc.lr_number;
        new_loc->lc_number2 = temp_loc.lr_number2;
        new_loc->lc_offset  = temp_loc.lr_offset;
        offset = nextoffset;

        if (head_loc == NULL)
            head_loc = prev_loc = new_loc;
        else {
            prev_loc->lc_next = new_loc;
            prev_loc = new_loc;
        }
    }

    block_loc =
        (Dwarf_Loc *) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK, op_count);
    if (block_loc == NULL) {
        /*  Some memory does leak here.  */
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return DW_DLV_ERROR;
    }

    new_loc = head_loc;
    for (i = 0; i < op_count; i++) {
        /* Copying only the fields needed by DWARF 2,3,4 */
        (block_loc + i)->lr_atom = new_loc->lc_atom;
        (block_loc + i)->lr_number = new_loc->lc_number;
        (block_loc + i)->lr_number2 = new_loc->lc_number2;
        (block_loc + i)->lr_offset = new_loc->lc_offset;
        prev_loc = new_loc;
        new_loc = prev_loc->lc_next;
        dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
    }

    locdesc =
        (Dwarf_Locdesc *) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC, 1);
    if (locdesc == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return DW_DLV_ERROR;
    }

    locdesc->ld_cents = op_count;
    locdesc->ld_s = block_loc;
    locdesc->ld_from_loclist = loc_block->bl_from_loclist;
    locdesc->ld_section_offset = loc_block->bl_section_offset;
    locdesc->ld_lopc = lowpc;
    locdesc->ld_hipc = highpc;

    *locdesc_out = locdesc;
    return DW_DLV_OK;
}
예제 #20
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);
}
예제 #21
0
/* Internal function called from various places to create
   lists of CIEs and FDEs.  Not directly called
   by consumer code */
int
_dwarf_get_fde_list_internal(Dwarf_Debug dbg, Dwarf_Cie ** cie_data,
			     Dwarf_Signed * cie_element_count,
			     Dwarf_Fde ** fde_data,
			     Dwarf_Signed * fde_element_count,
			     Dwarf_Small * section_ptr,
			     Dwarf_Unsigned section_index,
			     Dwarf_Unsigned section_length,
			     Dwarf_Unsigned cie_id_value,
			     int use_gnu_cie_calc, Dwarf_Error * error)
{
    /* Scans the debug_frame section. */
    Dwarf_Small *frame_ptr = section_ptr;
    Dwarf_Small *frame_ptr_end = section_ptr + section_length;



    /* 
       New_cie points to the Cie being read, and head_cie_ptr and
       cur_cie_ptr are used for chaining them up in sequence. */
    Dwarf_Cie head_cie_ptr = NULL;
    Dwarf_Cie cur_cie_ptr = NULL;
    Dwarf_Word cie_count = 0;

    /* 
       Points to a list of contiguous pointers to Dwarf_Cie structures. 
     */
    Dwarf_Cie *cie_list_ptr = 0;


    /* 
       New_fde points to the Fde being created, and head_fde_ptr and
       cur_fde_ptr are used to chain them up. */
    Dwarf_Fde head_fde_ptr = NULL;
    Dwarf_Fde cur_fde_ptr = NULL;
    Dwarf_Word fde_count = 0;

    /* 
       Points to a list of contiguous pointers to Dwarf_Fde structures. 
     */
    Dwarf_Fde *fde_list_ptr = NULL;

    Dwarf_Word i = 0;
    int res = 0;

    if (frame_ptr == 0) {
	return DW_DLV_NO_ENTRY;
    }

    /* We create the fde and cie arrays. Processing each CIE as we come 
       to it or as an FDE refers to it.  We cannot process 'late' CIEs
       late as GNU .eh_frame complexities mean we need the whole CIE
       before we can process the FDE correctly. */
    while (frame_ptr < frame_ptr_end) {

	struct cie_fde_prefix_s prefix;

	/* First read in the 'common prefix' to figure out what we are
	   to do with this entry. */
	memset(&prefix, 0, sizeof(prefix));
	res = dwarf_read_cie_fde_prefix(dbg,
					frame_ptr, section_ptr,
					section_index,
					section_length, &prefix, error);
	if (res == DW_DLV_ERROR) {
	    dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
	    return res;
	}
	if (res == DW_DLV_NO_ENTRY)
	    break;
	frame_ptr = prefix.cf_addr_after_prefix;
	if (frame_ptr >= frame_ptr_end) {
	    dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
	    _dwarf_error(dbg, error, DW_DLE_DEBUG_FRAME_LENGTH_BAD);
	    return DW_DLV_ERROR;

	}

	if (prefix.cf_cie_id == cie_id_value) {
	    /* This is a CIE.  */
	    Dwarf_Cie cie_ptr_to_use = 0;

	    int res = dwarf_find_existing_cie_ptr(prefix.cf_start_addr,
						  cur_cie_ptr,
						  &cie_ptr_to_use,
						  head_cie_ptr);

	    if (res == DW_DLV_OK) {
		cur_cie_ptr = cie_ptr_to_use;
		/* Ok. Seen already. */
	    } else if (res == DW_DLV_NO_ENTRY) {
		/* CIE before its FDE in this case. */
		res = dwarf_create_cie_from_after_start(dbg,
							&prefix,
							frame_ptr,
							cie_count,
							use_gnu_cie_calc,
							&cie_ptr_to_use,
							error);
		/* ASSERT: res==DW_DLV_NO_ENTRY impossible. */
		if (res == DW_DLV_ERROR) {
		    dealloc_fde_cie_list_internal(head_fde_ptr,
						  head_cie_ptr);
		    return res;
		}
		/* ASSERT res != DW_DLV_NO_ENTRY */
		cie_count++;
		chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
			     &cur_cie_ptr);
	    } else {		/* res == DW_DLV_ERROR */

		dealloc_fde_cie_list_internal(head_fde_ptr,
					      head_cie_ptr);
		return res;
	    }
	    frame_ptr = cie_ptr_to_use->ci_cie_start +
		cie_ptr_to_use->ci_length +
		cie_ptr_to_use->ci_length_size +
		cie_ptr_to_use->ci_extension_size;
	    continue;
	} else {
	    /* this is an FDE, Frame Description Entry, see the Dwarf
	       Spec, section 6.4.1 */
	    int res = 0;
	    Dwarf_Cie cie_ptr_to_use = 0;
	    Dwarf_Fde fde_ptr_to_use = 0;

	    /* Do not call this twice on one prefix, as
	       prefix.cf_cie_id_addr is altered as a side effect. */
	    Dwarf_Small *cieptr_val =
		get_cieptr_given_offset(prefix.cf_cie_id,
					use_gnu_cie_calc,
					section_ptr,
					prefix.cf_cie_id_addr);

	    res = dwarf_find_existing_cie_ptr(cieptr_val,
					      cur_cie_ptr,
					      &cie_ptr_to_use,
					      head_cie_ptr);
	    if (res == DW_DLV_OK) {
		cur_cie_ptr = cie_ptr_to_use;
		/* Ok. Seen CIE already. */
	    } else if (res == DW_DLV_NO_ENTRY) {
		res = dwarf_create_cie_from_start(dbg,
						  cieptr_val,
						  section_ptr,
						  section_index,
						  section_length,
						  frame_ptr_end,
						  cie_id_value,
						  cie_count,
						  use_gnu_cie_calc,
						  &cie_ptr_to_use,
						  error);
		if (res == DW_DLV_ERROR) {
		    dealloc_fde_cie_list_internal(head_fde_ptr,
						  head_cie_ptr);
		    return res;
		} else if (res == DW_DLV_NO_ENTRY) {
		    return res;
		}
		++cie_count;
		chain_up_cie(cie_ptr_to_use, &head_cie_ptr,
			     &cur_cie_ptr);

	    } else {
		/* DW_DLV_ERROR */
		return res;
	    }

	    res = dwarf_create_fde_from_after_start(dbg,
						    &prefix,
						    frame_ptr,
						    use_gnu_cie_calc,
						    cie_ptr_to_use,
						    &fde_ptr_to_use,
						    error);
	    if (res == DW_DLV_ERROR) {
		return res;
	    }
	    chain_up_fde(fde_ptr_to_use, &head_fde_ptr, &cur_fde_ptr);
	    fde_count++;
	    /* ASSERT: DW_DLV_OK. */
	    frame_ptr = fde_ptr_to_use->fd_fde_start +
		fde_ptr_to_use->fd_length +
		fde_ptr_to_use->fd_length_size +
		fde_ptr_to_use->fd_extension_size;
	    continue;

	}

    }

    /* Now build list of CIEs from the list. */
    if (cie_count > 0) {
	cie_list_ptr = (Dwarf_Cie *)
	    _dwarf_get_alloc(dbg, DW_DLA_LIST, cie_count);
    } else {
	dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
	return (DW_DLV_NO_ENTRY);
    }
    if (cie_list_ptr == NULL) {
	dealloc_fde_cie_list_internal(head_fde_ptr, head_cie_ptr);
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }
    cur_cie_ptr = head_cie_ptr;
    for (i = 0; i < cie_count; i++) {
	*(cie_list_ptr + i) = cur_cie_ptr;
	cur_cie_ptr = cur_cie_ptr->ci_next;
    }



    /* Now build array of FDEs from the list. */
    if (fde_count > 0) {
	fde_list_ptr = (Dwarf_Fde *)
	    _dwarf_get_alloc(dbg, DW_DLA_LIST, fde_count);
    } else {
	dwarf_fde_cie_list_dealloc(dbg, cie_list_ptr, cie_count,
				   /* fde_data */ 0,
				   /* fde_element_count */ 0);
	dealloc_fde_cie_list_internal(head_fde_ptr,	/* head cie_ptr 
							 */
				      0);
	return (DW_DLV_NO_ENTRY);
    }
    if (fde_list_ptr == NULL) {
	dwarf_fde_cie_list_dealloc(dbg, cie_list_ptr, cie_count,
				   /* fde_data */ 0,
				   /* fde_element_count */ 0);
	dealloc_fde_cie_list_internal(head_fde_ptr,	/* head cie_ptr 
							 */
				      0);
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }
    cur_fde_ptr = head_fde_ptr;
    for (i = 0; i < fde_count; i++) {
	*(fde_list_ptr + i) = cur_fde_ptr;
	cur_fde_ptr = cur_fde_ptr->fd_next;
    }


    /* Return arguments. */
    *cie_data = cie_list_ptr;
    *cie_element_count = cie_count;
    dbg->de_cie_data = cie_list_ptr;
    dbg->de_cie_count = cie_count;

    *fde_data = fde_list_ptr;
    *fde_element_count = fde_count;
    dbg->de_fde_data = fde_list_ptr;
    dbg->de_fde_count = fde_count;

    /* Sort the list by the address so that dwarf_get_fde_at_pc() can
       binary search this list. */
    qsort((void *) fde_list_ptr, fde_count, sizeof(Dwarf_Ptr),
	  qsort_compare);

    return (DW_DLV_OK);
}
예제 #22
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;
}
예제 #23
0
int
dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
				  struct cie_fde_prefix_s *prefix,
				  Dwarf_Small * frame_ptr,
				  int use_gnu_cie_calc,
				  Dwarf_Cie cie_ptr_in,
				  Dwarf_Fde * fde_ptr_out,
				  Dwarf_Error * error)
{
    Dwarf_Fde new_fde = 0;
    Dwarf_Cie cieptr = cie_ptr_in;
    Dwarf_Small *saved_frame_ptr = 0;

    Dwarf_Small *initloc = frame_ptr;
    Dwarf_Signed offset_into_exception_tables
	/* must be min dwarf_sfixed in size */
	= (Dwarf_Signed) DW_DLX_NO_EH_OFFSET;
    Dwarf_Small *fde_aug_data = 0;
    Dwarf_Unsigned fde_aug_data_len = 0;
    Dwarf_Addr cie_base_offset = prefix->cf_cie_id;
    Dwarf_Addr initial_location = 0;	/* must be min de_pointer_size
					   bytes in size */
    Dwarf_Addr address_range = 0;	/* must be min de_pointer_size
					   bytes in size */

    enum Dwarf_augmentation_type augt = cieptr->ci_augmentation_type;

    if (augt == aug_gcc_eh_z) {
	/* If z augmentation this is eh_frame, and initial_location and 
	   address_range in the FDE are read according to the CIE
	   augmentation string instructions.  */

	{
	    Dwarf_Small *fp_updated = 0;
	    int res = res = read_encoded_ptr(dbg, frame_ptr,
					     cieptr->
					     ci_gnu_fde_begin_encoding,
					     &initial_location,
					     &fp_updated);

	    if (res != DW_DLV_OK) {
		_dwarf_error(dbg, error,
			     DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
		return DW_DLV_ERROR;
	    }
	    frame_ptr = fp_updated;
	    res = read_encoded_ptr(dbg, frame_ptr,
				   cieptr->ci_gnu_fde_begin_encoding,
				   &address_range, &fp_updated);
	    if (res != DW_DLV_OK) {
		_dwarf_error(dbg, error,
			     DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
		return DW_DLV_ERROR;
	    }
	    frame_ptr = fp_updated;
	}
	{
	    Dwarf_Unsigned adlen = 0;

	    DECODE_LEB128_UWORD(frame_ptr, adlen);
	    fde_aug_data_len = adlen;
	    fde_aug_data = frame_ptr;
	    frame_ptr += adlen;
	}

    } else {
	READ_UNALIGNED(dbg, initial_location, Dwarf_Addr,
		       frame_ptr, dbg->de_pointer_size);
	frame_ptr += dbg->de_pointer_size;

	READ_UNALIGNED(dbg, address_range, Dwarf_Addr,
		       frame_ptr, dbg->de_pointer_size);
	frame_ptr += dbg->de_pointer_size;
    }





    switch (augt) {
    case aug_irix_mti_v1:
    case aug_empty_string:
	break;
    case aug_irix_exception_table:{
	    Dwarf_Unsigned lreg = 0;
	    Dwarf_Word length_of_augmented_fields = 0;

	    DECODE_LEB128_UWORD(frame_ptr, lreg);
	    length_of_augmented_fields = (Dwarf_Word) lreg;

	    saved_frame_ptr = frame_ptr;
	    /* The first word is an offset into exception tables.
	       Defined as a 32bit offset even for CC -64. */
	    READ_UNALIGNED(dbg, offset_into_exception_tables,
			   Dwarf_Addr, frame_ptr, sizeof(Dwarf_sfixed));
	    SIGN_EXTEND(offset_into_exception_tables,
			sizeof(Dwarf_sfixed));
	    frame_ptr = saved_frame_ptr + length_of_augmented_fields;
	}
	break;
    case aug_eh:{
	    Dwarf_Unsigned eh_table_value = 0;

	    if (!use_gnu_cie_calc) {
		/* This should be impossible. */
		_dwarf_error(dbg, error,
			     DW_DLE_FRAME_AUGMENTATION_UNKNOWN);
		return DW_DLV_ERROR;
	    }

	    /* gnu eh fde case. we do not need to do anything */
	     /*REFERENCED*/	/* Not used in this instance of the
				   macro */
		READ_UNALIGNED(dbg, eh_table_value,
			       Dwarf_Unsigned, frame_ptr,
			       dbg->de_pointer_size);
	    frame_ptr += dbg->de_pointer_size;
	}
	break;

    case aug_gcc_eh_z:{
	    /* The Augmentation Data Length is here, followed by the
	       Augmentation Data bytes themselves. */
	}
	break;
    }				/* End switch on augmentation type */
    new_fde = (Dwarf_Fde) _dwarf_get_alloc(dbg, DW_DLA_FDE, 1);
    if (new_fde == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    new_fde->fd_length = prefix->cf_length;
    new_fde->fd_length_size = prefix->cf_local_length_size;
    new_fde->fd_extension_size = prefix->cf_local_extension_size;
    new_fde->fd_cie_offset = cie_base_offset;
    new_fde->fd_cie_index = cieptr->ci_index;
    new_fde->fd_cie = cieptr;
    new_fde->fd_initial_location = initial_location;
    new_fde->fd_initial_loc_pos = initloc;
    new_fde->fd_address_range = address_range;
    new_fde->fd_fde_start = prefix->cf_start_addr;
    new_fde->fd_fde_instr_start = frame_ptr;
    new_fde->fd_dbg = dbg;
    new_fde->fd_offset_into_exception_tables =
	offset_into_exception_tables;

    new_fde->fd_section_ptr = prefix->cf_section_ptr;
    new_fde->fd_section_index = prefix->cf_section_index;
    new_fde->fd_section_length = prefix->cf_section_length;

    new_fde->fd_gnu_eh_augmentation_bytes = fde_aug_data;
    new_fde->fd_gnu_eh_augmentation_len = fde_aug_data_len;

    *fde_ptr_out = new_fde;
    return DW_DLV_OK;
}
예제 #24
0
/* 
    This routine works by looking for exact matches between 
    the current line address and pc, and crossovers from
    from less than pc value to greater than.  At each line
    that satisfies the above, it records a pointer to the
    line, and the difference between the address and pc.
    It then scans these pointers and picks out those with
    the smallest difference between pc and address.         
*/
int
dwarf_pclines(Dwarf_Debug dbg,
	      Dwarf_Addr pc,
	      Dwarf_Line ** linebuf,
	      Dwarf_Signed slide,
	      Dwarf_Signed * linecount, Dwarf_Error * error)
{
    /* 
       Scans the line matrix for the current cu to which a pointer
       exists in dbg. */
    Dwarf_Line line;
    Dwarf_Line prev_line;

    /* 
       These flags are for efficiency reasons. Check_line is true
       initially, but set false when the address of the current line
       is greater than pc.  It is set true only when the address of the 
       current line falls below pc.  This assumes that addresses
       within the same segment increase, and we are only interested in
       the switch from a less than pc address to a greater than.
       First_line is set true initially, but set false after the first
       line is scanned.  This is to prevent looking at the address of
       previous line when slide is DW_DLS_BACKWARD, and the first line
       is being scanned. */
    Dwarf_Bool check_line, first_line;

    /* 
       Diff tracks the smallest difference a line address and the
       input pc value. */
    Dwarf_Signed diff, i;

    /* 
       For the slide = DW_DLS_BACKWARD case, pc_less is the value of
       the address of the line immediately preceding the first line
       that has value greater than pc. For the slide = DW_DLS_FORWARD 
       case, pc_more is the values of address for the first line that
       is greater than pc. Diff is the difference between either of
       the these values and pc. */
    Dwarf_Addr pc_less, pc_more;

    /* 
       Pc_line_buf points to a chain of pointers to lines of which
       those with a diff equal to the smallest difference will be
       returned. */
    Dwarf_Line *pc_line_buf, *pc_line;

    /* 
       Chain_count counts the number of lines in the above chain for
       which the diff is equal to the smallest difference This is the
       number returned by this routine. */
    Dwarf_Signed chain_count;

    chain_head = NULL;

    check_line = true;
    first_line = true;
    diff = MAX_LINE_DIFF;

    for (i = 0; i < dbg->de_cu_line_count; i++) {

	line = *(dbg->de_cu_line_ptr + i);
	prev_line = first_line ? NULL : *(dbg->de_cu_line_ptr + i - 1);

	if (line->li_address == pc) {
	    chain_ptr = (struct chain *)
		_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
	    if (chain_ptr == NULL) {
		_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
		return (DW_DLV_ERROR);
	    }

	    chain_ptr->line = line;
	    chain_ptr->diff = diff = 0;
	    chain_ptr->next = chain_head;
	    chain_head = chain_ptr;
	} else
	    /* 
	       Look for crossover from less than pc address to greater 
	       than. */
	if (check_line && line->li_address > pc &&
		(first_line ? 0 : prev_line->li_address) < pc)

	    if (slide == DW_DLS_BACKWARD && !first_line) {
		pc_less = prev_line->li_address;
		if (pc - pc_less <= diff) {
		    chain_ptr = (struct chain *)
			_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
		    if (chain_ptr == NULL) {
			_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
			return (DW_DLV_ERROR);
		    }

		    chain_ptr->line = prev_line;
		    chain_ptr->diff = diff = pc - pc_less;
		    chain_ptr->next = chain_head;
		    chain_head = chain_ptr;
		}
		check_line = false;
	    } else if (slide == DW_DLS_FORWARD) {
		pc_more = line->li_address;
		if (pc_more - pc <= diff) {
		    chain_ptr = (struct chain *)
			_dwarf_get_alloc(dbg, DW_DLA_CHAIN, 1);
		    if (chain_ptr == NULL) {
			_dwarf_error(NULL, error, DW_DLE_ALLOC_FAIL);
			return (DW_DLV_ERROR);
		    }

		    chain_ptr->line = line;
		    chain_ptr->diff = diff = pc_more - pc;
		    chain_ptr->next = chain_head;
		    chain_head = chain_ptr;
		}
		check_line = false;
	    } else
		/* Check addresses only when they go */
		/* below pc.  */
	    if (line->li_address < pc)
		check_line = true;

	first_line = false;
    }

    chain_count = 0;
    for (chain_ptr = chain_head; chain_ptr != NULL;
	 chain_ptr = chain_ptr->next)
	if (chain_ptr->diff == diff)
	    chain_count++;

    pc_line_buf = pc_line = (Dwarf_Line)
	_dwarf_get_alloc(dbg, DW_DLA_LIST, chain_count);
    for (chain_ptr = chain_head; chain_ptr != NULL;
	 chain_ptr = chain_ptr->next)
	if (chain_ptr->diff == diff) {
	    *pc_line = chain_ptr->line;
	    pc_line++;
	}

    for (chain_ptr = chain_head; chain_ptr != NULL;) {
	chain_head = chain_ptr;
	chain_ptr = chain_ptr->next;
	dwarf_dealloc(dbg, chain_head, DW_DLA_CHAIN);
    }

    *linebuf = pc_line_buf;
    return (chain_count);
}
예제 #25
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)
{
    Dwarf_Unsigned i = 0;

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

    Dwarf_Signed arange_count = 0;
    Dwarf_Addr *arange_addrs = 0;
    Dwarf_Off *arange_offsets = 0;

    int res = DW_DLV_ERROR;

    /* ***** 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,error);
    if (res != DW_DLV_OK) {
        return res;
    }

    res = dwarf_get_aranges_list(dbg,&head_chain,&arange_count,error);
    if(res != DW_DLV_OK) {
        return res;
    }

    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);
}
예제 #26
0
int
dwarf_get_macro_details(Dwarf_Debug dbg,
                        Dwarf_Off macro_offset,
                        Dwarf_Unsigned maximum_count,
                        Dwarf_Signed * entry_count,
                        Dwarf_Macro_Details ** details,
                        Dwarf_Error * error)
{
    Dwarf_Small *macro_base = 0;
    Dwarf_Small *macro_end = 0;
    Dwarf_Small *pnext = 0;
    Dwarf_Unsigned endloc = 0;
    unsigned char uc = 0;
    unsigned long depth = 0;
    /* By section 6.3.2 Dwarf3 draft 8/9,
    the base file should appear as
    DW_MACINFO_start_file. See
    http://gcc.gnu.org/ml/gcc-bugs/2005-02/msg03442.html
    on "[Bug debug/20253] New: [3.4/4.0 regression]:
    Macro debug info broken due to lexer change" for how
    gcc is broken in some versions. We no longer use
    depth as a stopping point, it's not needed as a
    stopping point anyway.  */
    int res = 0;
    /* count space used by strings */
    unsigned long str_space = 0;
    int done = 0;
    unsigned long space_needed = 0;
    unsigned long string_offset = 0;
    Dwarf_Small *return_data = 0;
    Dwarf_Small *pdata = 0;
    unsigned long final_count = 0;
    Dwarf_Signed fileindex = -1;
    Dwarf_Small *latest_str_loc = 0;
    struct macro_stack_s msdata;

    unsigned long count = 0;
    unsigned long max_count = (unsigned long) maximum_count;

    _dwarf_reset_index_macro_stack(&msdata);
    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_ERROR);
    }

    res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error);
    if (res != DW_DLV_OK) {
        free_macro_stack(dbg,&msdata);
        return res;
    }
    if (!dbg->de_debug_abbrev.dss_size) {
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_NO_ENTRY);
    }

    macro_base = dbg->de_debug_macinfo.dss_data;
    if (macro_base == NULL) {
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_NO_ENTRY);
    }
    if (macro_offset >= dbg->de_debug_macinfo.dss_size) {
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_NO_ENTRY);
    }
    macro_end = macro_base + dbg->de_debug_macinfo.dss_size;
    /*   FIXME debugfission is NOT handled here.  */

    pnext = macro_base + macro_offset;
    if (maximum_count == 0) {
        max_count = ULONG_MAX;
    }


    /* how many entries and how much space will they take? */

    endloc = (pnext - macro_base);
    if (endloc >= dbg->de_debug_macinfo.dss_size) {
        if (endloc == dbg->de_debug_macinfo.dss_size) {
            /* normal: found last entry */
            free_macro_stack(dbg,&msdata);
            return DW_DLV_NO_ENTRY;
        }
        _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
        free_macro_stack(dbg,&msdata);
        return (DW_DLV_ERROR);
    }
    for (count = 0; !done && count < max_count; ++count) {
        unsigned long slen = 0;

        /* Set but not used */
        UNUSEDARG Dwarf_Unsigned utemp = 0;

        uc = *pnext;
        ++pnext;                /* get past the type code */
        switch (uc) {
        case DW_MACINFO_define:
        case DW_MACINFO_undef:
        /* line, string */
        case DW_MACINFO_vendor_ext:
            /* number, string */
            DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
                                   macro_end);
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            res = _dwarf_check_string_valid(dbg,
                                            macro_base,pnext,macro_end,error);
            if (res != DW_DLV_OK) {
                return res;
            }
            slen = strlen((char *) pnext) + 1;
            pnext += slen;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            str_space += slen;
            break;
        case DW_MACINFO_start_file:
            /* line, file index */
            DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
                                   macro_end);
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
                                   macro_end);
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            ++depth;
            break;

        case DW_MACINFO_end_file:
            if (--depth == 0) {
                /*  done = 1; no, do not stop here, at least one gcc had
                    the wrong depth settings in the gcc 3.4 timeframe. */
            }
            /* no string or number here */
            break;
        case 0:
            /* end of cu's entries */
            done = 1;
            break;
        default:
            free_macro_stack(dbg,&msdata);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
            return (DW_DLV_ERROR);
            /* bogus macinfo! */
        }

        endloc = (pnext - macro_base);
        if (endloc == dbg->de_debug_macinfo.dss_size) {
            done = 1;
        } else if (endloc > dbg->de_debug_macinfo.dss_size) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
            free_macro_stack(dbg,&msdata);
            return (DW_DLV_ERROR);
        }
    }
    if (count == 0) {
        free_macro_stack(dbg,&msdata);
        _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INTERNAL_ERR);
        return (DW_DLV_ERROR);
    }

    /*  We have 'count' array entries to allocate and str_space bytes of
        string space to provide for. */

    string_offset = count * sizeof(Dwarf_Macro_Details);

    /* extra 2 not really needed */
    space_needed = string_offset + str_space + 2;
    return_data = pdata =
                      (Dwarf_Small *)_dwarf_get_alloc(dbg, DW_DLA_STRING, space_needed);
    latest_str_loc = pdata + string_offset;
    if (pdata == 0) {
        free_macro_stack(dbg,&msdata);
        _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE);
        return (DW_DLV_ERROR);
    }
    pnext = macro_base + macro_offset;

    done = 0;

    /* A series ends with a type code of 0. */

    for (final_count = 0; !done && final_count < count; ++final_count) {
        unsigned long slen = 0;
        Dwarf_Unsigned v1 = 0;
        Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata +
                                    (final_count * sizeof (Dwarf_Macro_Details)));

        endloc = (pnext - macro_base);
        if (endloc > dbg->de_debug_macinfo.dss_size) {
            free_macro_stack(dbg,&msdata);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
            return (DW_DLV_ERROR);
        }
        uc = *pnext;
        pdmd->dmd_offset = (pnext - macro_base);
        pdmd->dmd_type = uc;
        pdmd->dmd_fileindex = fileindex;
        pdmd->dmd_lineno = 0;
        pdmd->dmd_macro = 0;
        ++pnext;                /* get past the type code */
        switch (uc) {
        case DW_MACINFO_define:
        case DW_MACINFO_undef:
        /* line, string */
        case DW_MACINFO_vendor_ext:
            /* number, string */
            DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
                                   macro_end);
            pdmd->dmd_lineno = v1;

            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            res = _dwarf_check_string_valid(dbg,
                                            macro_base,pnext,macro_end,error);
            if (res != DW_DLV_OK) {
                return res;
            }
            slen = strlen((char *) pnext) + 1;
            strcpy((char *) latest_str_loc, (char *) pnext);
            pdmd->dmd_macro = (char *) latest_str_loc;
            latest_str_loc += slen;
            pnext += slen;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            break;
        case DW_MACINFO_start_file:
            /* Line, file index */
            DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
                                   macro_end);
            pdmd->dmd_lineno = v1;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
                                   macro_end);
            pdmd->dmd_fileindex = v1;
            (void) _dwarf_macro_stack_push_index(dbg, fileindex,
                                                 &msdata);
            /*  We ignore the error, we just let fileindex ** be -1 when
                we pop this one. */
            fileindex = v1;
            if (((Dwarf_Unsigned)(pnext - macro_base)) >=
                    dbg->de_debug_macinfo.dss_size) {
                free_macro_stack(dbg,&msdata);
                dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
                _dwarf_error(dbg, error,
                             DW_DLE_DEBUG_MACRO_INCONSISTENT);
                return (DW_DLV_ERROR);
            }
            break;

        case DW_MACINFO_end_file:
            fileindex = _dwarf_macro_stack_pop_index(&msdata);
            break;              /* no string or number here */
        case 0:
            /* Type code of 0 means the end of cu's entries. */
            done = 1;
            break;
        default:
            /* Bogus macinfo! */
            dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
            free_macro_stack(dbg,&msdata);
            _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
            return (DW_DLV_ERROR);
        }
    }
    *entry_count = count;
    *details = (Dwarf_Macro_Details *) return_data;
    free_macro_stack(dbg,&msdata);
    return DW_DLV_OK;
}
예제 #27
0
/*  This code was contributed some time ago
    and the return
    value is in the wrong form,
    but we are not fixing it.
*/
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;
    unsigned 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_Word len = 0;
        _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;
}
예제 #28
0
파일: dwarf_util.c 프로젝트: finik/libdwarf
/*  This function returns a pointer to a Dwarf_Abbrev_List_s
    struct for the abbrev with the given code.  It puts the
    struct on the appropriate hash table.  It also adds all
    the abbrev between the last abbrev added and this one to
    the hash table.  In other words, the .debug_abbrev section
    is scanned sequentially from the top for an abbrev with
    the given code.  All intervening abbrevs are also put
    into the hash table.

    This function hashes the given code, and checks the chain
    at that hash table entry to see if a Dwarf_Abbrev_List_s
    with the given code exists.  If yes, it returns a pointer
    to that struct.  Otherwise, it scans the .debug_abbrev
    section from the last byte scanned for that CU till either
    an abbrev with the given code is found, or an abbrev code
    of 0 is read.  It puts Dwarf_Abbrev_List_s entries for all
    abbrev's read till that point into the hash table.  The
    hash table contains both a head pointer and a tail pointer
    for each entry.

    While the lists can move and entries can be moved between
    lists on reallocation, any given Dwarf_Abbrev_list entry
    never moves once allocated, so the pointer is safe to return.

    See also dwarf_get_abbrev() in dwarf_abbrev.c.

    Returns NULL on error.  */
int
_dwarf_get_abbrev_for_code(Dwarf_CU_Context cu_context, Dwarf_Unsigned code,
    Dwarf_Abbrev_List *list_out,
    Dwarf_Error *error)
{
    Dwarf_Debug dbg = cu_context->cc_dbg;
    Dwarf_Hash_Table hash_table_base = cu_context->cc_abbrev_hash_table;
    Dwarf_Hash_Table_Entry entry_base = 0;
    Dwarf_Hash_Table_Entry entry_cur = 0;
    Dwarf_Word hash_num = 0;
    Dwarf_Unsigned abbrev_code = 0;
    Dwarf_Unsigned abbrev_tag  = 0;
    Dwarf_Unsigned attr_name = 0;
    Dwarf_Unsigned attr_form = 0;
    Dwarf_Abbrev_List hash_abbrev_entry = 0;
    Dwarf_Abbrev_List inner_list_entry = 0;
    Dwarf_Hash_Table_Entry inner_hash_entry = 0;

    Dwarf_Byte_Ptr abbrev_ptr = 0;
    Dwarf_Byte_Ptr end_abbrev_ptr = 0;
    unsigned hashable_val = 0;

    if (!hash_table_base->tb_entries) {
        hash_table_base->tb_table_entry_count =  HT_MULTIPLE;
        hash_table_base->tb_total_abbrev_count= 0;
        hash_table_base->tb_entries =
            (struct  Dwarf_Hash_Table_Entry_s *)_dwarf_get_alloc(dbg,
            DW_DLA_HASH_TABLE_ENTRY,
            hash_table_base->tb_table_entry_count);
        if (!hash_table_base->tb_entries) {
            return DW_DLV_NO_ENTRY;
        }

    } else if (hash_table_base->tb_total_abbrev_count >
        ( hash_table_base->tb_table_entry_count * HT_MULTIPLE) ) {
        struct Dwarf_Hash_Table_s newht;
        /* Effectively multiplies by >= HT_MULTIPLE */
        newht.tb_table_entry_count =  hash_table_base->tb_total_abbrev_count;
        newht.tb_total_abbrev_count = 0;
        newht.tb_entries =
            (struct  Dwarf_Hash_Table_Entry_s *)_dwarf_get_alloc(dbg,
            DW_DLA_HASH_TABLE_ENTRY,
            newht.tb_table_entry_count);

        if (!newht.tb_entries) {
            return DW_DLV_NO_ENTRY;
        }
        /*  Copy the existing entries to the new table,
            rehashing each.  */
        copy_abbrev_table_to_new_table(hash_table_base, &newht);
        /*  Dealloc only the entries hash table array, not the lists
            of things pointed to by a hash table entry array. */
        dwarf_dealloc(dbg, hash_table_base->tb_entries,DW_DLA_HASH_TABLE_ENTRY);
        hash_table_base->tb_entries = 0;
        /*  Now overwrite the existing table descriptor with
            the new, newly valid, contents. */
        *hash_table_base = newht;
    } /* Else is ok as is, add entry */

    hashable_val = code;
    hash_num = hashable_val %
        hash_table_base->tb_table_entry_count;
    entry_base = hash_table_base->tb_entries;
    entry_cur  = entry_base + hash_num;

    /* Determine if the 'code' is the list of synonyms already. */
    for (hash_abbrev_entry = entry_cur->at_head;
        hash_abbrev_entry != NULL && hash_abbrev_entry->abl_code != code;
        hash_abbrev_entry = hash_abbrev_entry->abl_next);
    if (hash_abbrev_entry != NULL) {
        /*  This returns a pointer to an abbrev list entry, not
            the list itself. */
        *list_out = hash_abbrev_entry;
        return DW_DLV_OK;
    }

    if (cu_context->cc_last_abbrev_ptr) {
        abbrev_ptr = cu_context->cc_last_abbrev_ptr;
        end_abbrev_ptr = cu_context->cc_last_abbrev_endptr;
    } else {
        /*  This is ok because cc_abbrev_offset includes DWP
            offset if appropriate. */
        abbrev_ptr = dbg->de_debug_abbrev.dss_data +
            cu_context->cc_abbrev_offset;

        if (cu_context->cc_dwp_offsets.pcu_type)  {
            /*  In a DWP the abbrevs
                for this context are known quite precisely. */
            Dwarf_Unsigned size = 0;
            /* Ignore the offset returned. Already in cc_abbrev_offset. */
            _dwarf_get_dwp_extra_offset(&cu_context->cc_dwp_offsets,
                DW_SECT_ABBREV,&size);
            /*  ASSERT: size != 0 */
            end_abbrev_ptr = abbrev_ptr + size;
        } else {
            end_abbrev_ptr = abbrev_ptr +
                dbg->de_debug_abbrev.dss_size;
        }
    }

    /*  End of abbrev's as we are past the end entirely.
        This can happen. */
    if (abbrev_ptr > end_abbrev_ptr) {
        return DW_DLV_NO_ENTRY;
    }
    /*  End of abbrev's for this cu, since abbrev code is 0. */
    if (*abbrev_ptr == 0) {
        return DW_DLV_NO_ENTRY;
    }

    do {
        unsigned new_hashable_val = 0;
        Dwarf_Off  abb_goff = 0;
        Dwarf_Unsigned atcount = 0;

        abb_goff = abbrev_ptr - dbg->de_debug_abbrev.dss_data;
        DECODE_LEB128_UWORD(abbrev_ptr, abbrev_code);
        DECODE_LEB128_UWORD(abbrev_ptr, abbrev_tag);

        inner_list_entry = (Dwarf_Abbrev_List)
            _dwarf_get_alloc(cu_context->cc_dbg, DW_DLA_ABBREV_LIST, 1);
        if (inner_list_entry == NULL) {
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return DW_DLV_ERROR;
        }

        new_hashable_val = abbrev_code;
        hash_num = new_hashable_val %
            hash_table_base->tb_table_entry_count;
        inner_hash_entry = entry_base + hash_num;
        /* Move_entry_to_new_hash */
        inner_list_entry->abl_next = inner_hash_entry->at_head;
        inner_hash_entry->at_head = inner_list_entry;

        hash_table_base->tb_total_abbrev_count++;

        inner_list_entry->abl_code = abbrev_code;
        inner_list_entry->abl_tag = abbrev_tag;
        inner_list_entry->abl_has_child = *(abbrev_ptr++);
        inner_list_entry->abl_abbrev_ptr = abbrev_ptr;
        inner_list_entry->abl_goffset =  abb_goff;

        hash_table_base->tb_total_abbrev_count++;

        /*  Cycle thru the abbrev content, ignoring the content except
            to find the end of the content. */
        do {
            DECODE_LEB128_UWORD(abbrev_ptr, attr_name);
            DECODE_LEB128_UWORD(abbrev_ptr, attr_form);
            if (!_dwarf_valid_form_we_know(dbg,attr_form,attr_name)) {
                _dwarf_error(dbg,error,DW_DLE_UNKNOWN_FORM);
                return DW_DLV_ERROR;
            }
            atcount++;
        } while (attr_name != 0 && attr_form != 0);
        /*  We counted one too high, by counting the NUL
            byte pair at end of list. So decrement. */
        inner_list_entry->abl_count = atcount-1;

        /*  We may have fallen off the end of content,  that is not
            a botch in the section, as there is no rule that the last
            abbrev need have abbrev_code of 0. */

    } while ((abbrev_ptr < end_abbrev_ptr) &&
        *abbrev_ptr != 0 && abbrev_code != code);

    cu_context->cc_last_abbrev_ptr = abbrev_ptr;
    cu_context->cc_last_abbrev_endptr = end_abbrev_ptr;
    if(abbrev_code == code) {
        *list_out = inner_list_entry;
        return DW_DLV_OK;
    }
    return DW_DLV_NO_ENTRY;
}
예제 #29
0
int
dwarf_linesrc(Dwarf_Line line, char **ret_linesrc, Dwarf_Error * error)
{
    Dwarf_Signed i;
    Dwarf_File_Entry file_entry;
    Dwarf_Small *name_buffer;
    Dwarf_Small *include_directories;
    Dwarf_Debug dbg;
    unsigned int comp_dir_len;

    if (line == NULL) {
	_dwarf_error(NULL, error, DW_DLE_DWARF_LINE_NULL);
	return (DW_DLV_ERROR);
    }

    if (line->li_context == NULL) {
	_dwarf_error(NULL, error, DW_DLE_LINE_CONTEXT_NULL);
	return (DW_DLV_ERROR);
    }
    dbg = line->li_context->lc_dbg;

    if (line->li_addr_line.li_l_data.li_file >
	line->li_context->lc_file_entry_count) {
	_dwarf_error(dbg, error, DW_DLE_LINE_FILE_NUM_BAD);
	return (DW_DLV_ERROR);
    }

    file_entry = line->li_context->lc_file_entries;
    for (i = line->li_addr_line.li_l_data.li_file - 1; i > 0; i--)
	file_entry = file_entry->fi_next;

    if (file_entry->fi_file_name == NULL) {
	_dwarf_error(dbg, error, DW_DLE_NO_FILE_NAME);
	return (DW_DLV_ERROR);
    }

    if (*(char *) file_entry->fi_file_name == '/') {
	*ret_linesrc = ((char *) file_entry->fi_file_name);
	return DW_DLV_OK;
    }

    if (file_entry->fi_dir_index == 0) {

	/* dir_index of 0 means that the compilation was in the
	   'current directory of compilation' */
	if (line->li_context->lc_compilation_directory == NULL) {
	    /* we don't actually *have* a current directory of
	       compilation: DW_AT_comp_dir was not present Rather than
	       emitting DW_DLE_NO_COMP_DIR lets just make an empty name 
	       here. In other words, do the best we can with what we do 
	       have instead of reporting an error. _dwarf_error(dbg,
	       error, DW_DLE_NO_COMP_DIR); return(DW_DLV_ERROR); */
	    comp_dir_len = 0;
	} else {
	    comp_dir_len = strlen((char *)
				  (line->li_context->
				   lc_compilation_directory));
	}

	name_buffer =
	    _dwarf_get_alloc(line->li_context->lc_dbg, DW_DLA_STRING,
			     comp_dir_len + 1 +
			     strlen((char *) file_entry->fi_file_name) +
			     1);
	if (name_buffer == NULL) {
	    _dwarf_error(line->li_context->lc_dbg, error,
			 DW_DLE_ALLOC_FAIL);
	    return (DW_DLV_ERROR);
	}

	if (comp_dir_len > 0) {
	    /* if comp_dir_len is 0 we do not want to put a / in front
	       of the fi_file_name as we just don't know anything. */
	    strcpy((char *) name_buffer,
		   (char *) (line->li_context->
			     lc_compilation_directory));
	    strcat((char *) name_buffer, "/");
	}
	strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
	*ret_linesrc = ((char *) name_buffer);
	return DW_DLV_OK;
    }

    if (file_entry->fi_dir_index >
	line->li_context->lc_include_directories_count) {
	_dwarf_error(dbg, error, DW_DLE_INCL_DIR_NUM_BAD);
	return (DW_DLV_ERROR);
    }

    include_directories = line->li_context->lc_include_directories;
    for (i = file_entry->fi_dir_index - 1; i > 0; i--)
	include_directories += strlen((char *) include_directories) + 1;

    if (line->li_context->lc_compilation_directory) {
	comp_dir_len = strlen((char *)
			      (line->li_context->
			       lc_compilation_directory));
    } else {
	/* No DW_AT_comp_dir present. Do the best we can without it. */
	comp_dir_len = 0;
    }

    name_buffer = _dwarf_get_alloc(dbg, DW_DLA_STRING,
				   (*include_directories == '/' ?
				    0 : comp_dir_len + 1) +
				   strlen((char *) include_directories)
				   + 1 +
				   strlen((char *) file_entry->
					  fi_file_name) + 1);
    if (name_buffer == NULL) {
	_dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
	return (DW_DLV_ERROR);
    }

    if (*include_directories != '/') {
	if (comp_dir_len > 0) {
	    strcpy((char *) name_buffer,
		   (char *) line->li_context->lc_compilation_directory);
	    /* Who provides the / needed after the compilation
	       directory? */
	    if (name_buffer[comp_dir_len - 1] != '/') {
		/* Here we provide the / separator */
		name_buffer[comp_dir_len] = '/';	/* overwrite
							   previous nul 
							   terminator
							   with needed
							   / */
		name_buffer[comp_dir_len + 1] = 0;
	    }
	}
    } else {
	strcpy((char *) name_buffer, "");
    }
    strcat((char *) name_buffer, (char *) include_directories);
    strcat((char *) name_buffer, "/");
    strcat((char *) name_buffer, (char *) file_entry->fi_file_name);
    *ret_linesrc = ((char *) name_buffer);
    return DW_DLV_OK;
}
예제 #30
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);
}