示例#1
0
void
_dwarf_set_error(Dwarf_Debug dbg, Dwarf_Error *error, int errorcode,
    int elferrorcode, const char *functionname, int linenumber)
{
	Dwarf_Error de;

	de.err_error = errorcode;
	de.err_elferror = elferrorcode;
	de.err_func  = functionname;
	de.err_line  = linenumber;
	de.err_msg[0] = '\0';
	
	/*
	 * If the user supplied a destination for the error, copy the
	 * error descriptor over and return.  Otherwise, if the debug
	 * context is known and has an error handler, invoke that.
	 * Otherwise, if a 'default' error handler was registered,
	 * invoke it.
	 */
	if (error)
		*error = de;
	else if (dbg && dbg->dbg_errhand)
		dbg->dbg_errhand(de, dbg->dbg_errarg);
	else if (_libdwarf.errhand)
		_libdwarf.errhand(de, _libdwarf.errarg);

	/* No handler found, do nothing. */
}
示例#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.
*/
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();
}
示例#3
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();
}
/*
 * Given an array of bytes of length 'len' representing a
 * DWARF expression, compute the number of operations based
 * on there being one byte describing the operation and
 * zero or more bytes of operands as defined in the standard
 * for each operation type. Also, if lbuf is non-null, store
 * the opcode and oprand in it.
 */
static int
_dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
    uint8_t *p, int len)
{
	int count;
	uint64_t operand1;
	uint64_t operand2;
	uint8_t *ps, *pe;

	count = 0;
	ps = p;
	pe = p + len;

	/*
	 * Process each byte. If an error occurs, then the
	 * count will be set to -1.
	 */
	while (p < pe) {

		operand1 = 0;
		operand2 = 0;

		if (lbuf != NULL) {
			lbuf->ld_s[count].lr_atom = *p;
			lbuf->ld_s[count].lr_offset = p - ps;
		}

		switch (*p++) {
		/* Operations with no operands. */
		case DW_OP_deref:
		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:

		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:

		case DW_OP_dup:
		case DW_OP_drop:

		case DW_OP_over:

		case DW_OP_swap:
		case DW_OP_rot:
		case DW_OP_xderef:

		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:

		case DW_OP_shl:
		case DW_OP_shr:
		case DW_OP_shra:
		case DW_OP_xor:

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

		case DW_OP_nop:
		case DW_OP_form_tls_address:
		case DW_OP_call_frame_cfa:
		case DW_OP_stack_value:
		case DW_OP_GNU_push_tls_address:
			break;

		/* Operations with 1-byte operands. */
		case DW_OP_const1u:
		case DW_OP_const1s:
		case DW_OP_pick:
		case DW_OP_deref_size:
		case DW_OP_xderef_size:
			operand1 = *p++;
			break;

		/* Operations with 2-byte operands. */
		case DW_OP_call2:
		case DW_OP_const2u:
		case DW_OP_const2s:
		case DW_OP_bra:
		case DW_OP_skip:
			operand1 = dbg->decode(&p, 2);
			break;

		/* Operations with 4-byte operands. */
		case DW_OP_call4:
		case DW_OP_const4u:
		case DW_OP_const4s:
			operand1 = dbg->decode(&p, 4);
			break;

		/* Operations with 8-byte operands. */
		case DW_OP_const8u:
		case DW_OP_const8s:
			operand1 = dbg->decode(&p, 8);
			break;

		/* Operations with an unsigned LEB128 operand. */
		case DW_OP_constu:
		case DW_OP_plus_uconst:
		case DW_OP_regx:
		case DW_OP_piece:
			operand1 = _dwarf_decode_uleb128(&p);
			break;

		/* Operations with a signed LEB128 operand. */
		case DW_OP_consts:
		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:
		case DW_OP_fbreg:
			operand1 = _dwarf_decode_sleb128(&p);
			break;

		/*
		 * Oeration with two unsigned LEB128 operands.
		 */
		case DW_OP_bit_piece:
			operand1 = _dwarf_decode_uleb128(&p);
			operand2 = _dwarf_decode_uleb128(&p);
			break;

		/*
		 * Operations with an unsigned LEB128 operand
		 * followed by a signed LEB128 operand.
		 */
		case DW_OP_bregx:
			operand1 = _dwarf_decode_uleb128(&p);
			operand2 = _dwarf_decode_sleb128(&p);
			break;

		/*
		 * Operation with an unsigned LEB128 operand
		 * followed by a block. Store a pointer to the
		 * block in the operand2.
		 */
		case DW_OP_implicit_value:
			operand1 = _dwarf_decode_uleb128(&p);
			operand2 = (Dwarf_Unsigned) (uintptr_t) p;
			p += operand1;
			break;

		/* Target address size operand. */
		case DW_OP_addr:
			operand1 = dbg->decode(&p, pointer_size);
			break;

		/*
		 * XXX Opcode DW_OP_call_ref has an operand with size
		 * "dwarf_size". Here we use dbg->dbg_offset_size
		 * as "dwarf_size" to be compatible with SGI libdwarf.
		 * However note that dbg->dbg_offset_size is just
		 * a "guess" value so the parsing result of
		 * DW_OP_call_ref might not be correct at all. XXX
		 */
		case DW_OP_call_ref:
			operand1 = dbg->decode(&p, dbg->dbg_offset_size);
			break;

		/* All other operations cause an error. */
		default:
			count = -1;
			break;
		}

		if (lbuf != NULL) {
			lbuf->ld_s[count].lr_number = operand1;
			lbuf->ld_s[count].lr_number2 = operand2;
		}

		count++;
	}

	return (count);
}
int
_dwarf_loc_expr_add_atom(Dwarf_Debug dbg, uint8_t *out, uint8_t *end,
    Dwarf_Small atom, Dwarf_Unsigned operand1, Dwarf_Unsigned operand2,
    int *length, Dwarf_Error *error)
{
	uint8_t buf[64];
	uint8_t *p, *pe;
	uint64_t offset;
	int len;

	if (out != NULL && end != NULL) {
		p = out;
		pe = end;
	} else {
		p = out = buf;
		pe = &buf[sizeof(buf)];
	}

	switch (atom) {
	/* Operations with no operands. */
	case DW_OP_deref:
	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:

	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:

	case DW_OP_dup:
	case DW_OP_drop:

	case DW_OP_over:

	case DW_OP_swap:
	case DW_OP_rot:
	case DW_OP_xderef:

	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:

	case DW_OP_shl:
	case DW_OP_shr:
	case DW_OP_shra:
	case DW_OP_xor:

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

	case DW_OP_nop:
	case DW_OP_GNU_push_tls_address:
		*p++ = atom;
		break;

	/* Operations with 1-byte operands. */
	case DW_OP_const1u:
	case DW_OP_const1s:
	case DW_OP_pick:
	case DW_OP_deref_size:
	case DW_OP_xderef_size:
		*p++ = atom;
		*p++ = (uint8_t) operand1;
		break;

	/* Operations with 2-byte operands. */
	case DW_OP_const2u:
	case DW_OP_const2s:
	case DW_OP_bra:
	case DW_OP_skip:
		*p++ = atom;
		offset = 0;
		dbg->write(p, &offset, operand1, 2);
		p += 2;
		break;

	/* Operations with 4-byte operands. */
	case DW_OP_const4u:
	case DW_OP_const4s:
		*p++ = atom;
		offset = 0;
		dbg->write(p, &offset, operand1, 4);
		p += 4;
		break;

	/* Operations with 8-byte operands. */
	case DW_OP_const8u:
	case DW_OP_const8s:
		*p++ = atom;
		offset = 0;
		dbg->write(p, &offset, operand1, 8);
		p += 8;
		break;

	/* Operations with an unsigned LEB128 operand. */
	case DW_OP_constu:
	case DW_OP_plus_uconst:
	case DW_OP_regx:
	case DW_OP_piece:
		*p++ = atom;
		len = _dwarf_write_uleb128(p, pe, operand1);
		assert(len > 0);
		p += len;
		break;

	/* Operations with a signed LEB128 operand. */
	case DW_OP_consts:
	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:
	case DW_OP_fbreg:
		*p++ = atom;
		len = _dwarf_write_sleb128(p, pe, operand1);
		assert(len > 0);
		p += len;
		break;

	/*
	 * Operations with an unsigned LEB128 operand
	 * followed by a signed LEB128 operand.
	 */
	case DW_OP_bregx:
		*p++ = atom;
		len = _dwarf_write_uleb128(p, pe, operand1);
		assert(len > 0);
		p += len;
		len = _dwarf_write_sleb128(p, pe, operand2);
		assert(len > 0);
		p += len;
		break;

	/* Target address size operand. */
	case DW_OP_addr:
		*p++ = atom;
		offset = 0;
		dbg->write(p, &offset, operand1, dbg->dbg_pointer_size);
		p += dbg->dbg_pointer_size;
		break;

	/* All other operations cause an error. */
	default:
		DWARF_SET_ERROR(dbg, error, DW_DLE_LOC_EXPR_BAD);
		return (DW_DLE_LOC_EXPR_BAD);
	}

	if (length)
		*length = p - out;

	return (DW_DLE_NONE);
}
static int
_dwarf_lineno_run_program(Dwarf_CU *cu, Dwarf_LineInfo li, uint8_t *p,
    uint8_t *pe, Dwarf_Addr pc, Dwarf_Error *error)
{
    Dwarf_Line ln, tln;
    uint64_t address, file, line, column, isa, opsize;
    int is_stmt, basic_block, end_sequence;
    int prologue_end, epilogue_begin;
    int ret;

	ln = &li->li_line;
#define RESET_REGISTERS                     \
    do {                            \
        address        = 0;             \
        file           = 1;             \
        line           = 1;             \
        column         = 0;             \
        is_stmt        = li->li_defstmt;        \
        basic_block    = 0;             \
        end_sequence   = 0;             \
        prologue_end   = 0;             \
        epilogue_begin = 0;             \
    } while(0)

#define APPEND_ROW                      \
    do {                            \
        if (pc < address) {               \
			return DW_DLE_NONE;			\
        }                       \
        ln->ln_addr   = address;            \
        ln->ln_symndx = 0;              \
        ln->ln_fileno = file;               \
        ln->ln_lineno = line;               \
        ln->ln_column = column;             \
        ln->ln_bblock = basic_block;            \
        ln->ln_stmt   = is_stmt;            \
        ln->ln_endseq = end_sequence;           \
        li->li_lnlen++;                 \
    } while(0)

#define LINE(x) (li->li_lbase + (((x) - li->li_opbase) % li->li_lrange))
#define ADDRESS(x) ((((x) - li->li_opbase) / li->li_lrange) * li->li_minlen)

    /*
     *   ln->ln_li     = li;             \
     * Set registers to their default values.
     */
    RESET_REGISTERS;

    /*
     * Start line number program.
     */
    while (p < pe) {
        if (*p == 0) {

            /*
             * Extended Opcodes.
             */

            p++;
            opsize = _dwarf_decode_uleb128(&p);
            switch (*p) {
            case DW_LNE_end_sequence:
                p++;
                end_sequence = 1;
                RESET_REGISTERS;
                break;
            case DW_LNE_set_address:
                p++;
                address = dbg->decode(&p, cu->addr_size);
                break;
            case DW_LNE_define_file:
                p++;
                ret = _dwarf_lineno_add_file(li, &p, NULL,
                    error, dbg);
                if (ret != DW_DLE_NONE)
                    goto prog_fail;
                break;
            default:
                /* Unrecognized extened opcodes. */
                p += opsize;
            }

        } else if (*p > 0 && *p < li->li_opbase) {

            /*
             * Standard Opcodes.
             */

            switch (*p++) {
            case DW_LNS_copy:
                APPEND_ROW;
                basic_block = 0;
                prologue_end = 0;
                epilogue_begin = 0;
                break;
            case DW_LNS_advance_pc:
                address += _dwarf_decode_uleb128(&p) *
                    li->li_minlen;
                break;
            case DW_LNS_advance_line:
                line += _dwarf_decode_sleb128(&p);
                break;
            case DW_LNS_set_file:
                file = _dwarf_decode_uleb128(&p);
                break;
            case DW_LNS_set_column:
                column = _dwarf_decode_uleb128(&p);
                break;
            case DW_LNS_negate_stmt:
                is_stmt = !is_stmt;
                break;
            case DW_LNS_set_basic_block:
                basic_block = 1;
                break;
            case DW_LNS_const_add_pc:
                address += ADDRESS(255);
                break;
            case DW_LNS_fixed_advance_pc:
                address += dbg->decode(&p, 2);
                break;
            case DW_LNS_set_prologue_end:
                prologue_end = 1;
                break;
            case DW_LNS_set_epilogue_begin:
                epilogue_begin = 1;
                break;
            case DW_LNS_set_isa:
                isa = _dwarf_decode_uleb128(&p);
                break;
            default:
                /* Unrecognized extened opcodes. What to do? */
                break;
            }

        } else {

            /*
             * Special Opcodes.
             */

            line += LINE(*p);
            address += ADDRESS(*p);
            APPEND_ROW;
            basic_block = 0;
            prologue_end = 0;
            epilogue_begin = 0;
            p++;
        }
    }

    return (DW_DLE_NONE);

prog_fail:

    return (ret);

#undef  RESET_REGISTERS
#undef  APPEND_ROW
#undef  LINE
#undef  ADDRESS
}
示例#7
0
/*
 * Given an array of bytes of length 'len' representing a
 * DWARF expression, compute the number of operations based
 * on there being one byte describing the operation and
 * zero or more bytes of operands as defined in the standard
 * for each operation type. Also, if lbuf is non-null, store
 * the opcode and oprand in it.
 */
static int
_dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
    uint8_t offset_size, uint8_t version, uint8_t *p, int len)
{
	int count;
	uint64_t operand1;
	uint64_t operand2;
	uint8_t *ps, *pe, s;

	count = 0;
	ps = p;
	pe = p + len;

	/*
	 * Process each byte. If an error occurs, then the
	 * count will be set to -1.
	 */
	while (p < pe) {

		operand1 = 0;
		operand2 = 0;

		if (lbuf != NULL) {
			lbuf->ld_s[count].lr_atom = *p;
			lbuf->ld_s[count].lr_offset = p - ps;
		}

		switch (*p++) {
		/* Operations with no operands. */
		case DW_OP_deref:
		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:

		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:

		case DW_OP_dup:
		case DW_OP_drop:

		case DW_OP_over:

		case DW_OP_swap:
		case DW_OP_rot:
		case DW_OP_xderef:

		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:

		case DW_OP_shl:
		case DW_OP_shr:
		case DW_OP_shra:
		case DW_OP_xor:

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

		case DW_OP_nop:
		case DW_OP_push_object_address:
		case DW_OP_form_tls_address:
		case DW_OP_call_frame_cfa:
		case DW_OP_stack_value:
		case DW_OP_GNU_push_tls_address:
		case DW_OP_GNU_uninit:
			break;

		/* Operations with 1-byte operands. */
		case DW_OP_const1u:
		case DW_OP_pick:
		case DW_OP_deref_size:
		case DW_OP_xderef_size:
			operand1 = *p++;
			break;

		case DW_OP_const1s:
			operand1 = (int8_t) *p++;
			break;

		/* Operations with 2-byte operands. */
		case DW_OP_call2:
		case DW_OP_const2u:
		case DW_OP_bra:
		case DW_OP_skip:
			operand1 = dbg->decode(&p, 2);
			break;

		case DW_OP_const2s:
			operand1 = (int16_t) dbg->decode(&p, 2);
			break;

		/* Operations with 4-byte operands. */
		case DW_OP_call4:
		case DW_OP_const4u:
		case DW_OP_GNU_parameter_ref:
			operand1 = dbg->decode(&p, 4);
			break;

		case DW_OP_const4s:
			operand1 = (int32_t) dbg->decode(&p, 4);
			break;

		/* Operations with 8-byte operands. */
		case DW_OP_const8u:
		case DW_OP_const8s:
			operand1 = dbg->decode(&p, 8);
			break;

		/* Operations with an unsigned LEB128 operand. */
		case DW_OP_constu:
		case DW_OP_plus_uconst:
		case DW_OP_regx:
		case DW_OP_piece:
		case DW_OP_GNU_deref_type:
		case DW_OP_GNU_convert:
		case DW_OP_GNU_reinterpret:
			operand1 = _dwarf_decode_uleb128(&p);
			break;

		/* Operations with a signed LEB128 operand. */
		case DW_OP_consts:
		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:
		case DW_OP_fbreg:
			operand1 = _dwarf_decode_sleb128(&p);
			break;

		/*
		 * Oeration with two unsigned LEB128 operands.
		 */
		case DW_OP_bit_piece:
		case DW_OP_GNU_regval_type:
			operand1 = _dwarf_decode_uleb128(&p);
			operand2 = _dwarf_decode_uleb128(&p);
			break;

		/*
		 * Operations with an unsigned LEB128 operand
		 * followed by a signed LEB128 operand.
		 */
		case DW_OP_bregx:
			operand1 = _dwarf_decode_uleb128(&p);
			operand2 = _dwarf_decode_sleb128(&p);
			break;

		/*
		 * Operation with an unsigned LEB128 operand
		 * representing the size of a block, followed
		 * by the block content.
		 *
		 * Store the size of the block in the operand1
		 * and a pointer to the block in the operand2.
		 */
		case DW_OP_implicit_value:
		case DW_OP_GNU_entry_value:
			operand1 = _dwarf_decode_uleb128(&p);
			operand2 = (Dwarf_Unsigned) (uintptr_t) p;
			p += operand1;
			break;

		/* Target address size operand. */
		case DW_OP_addr:
		case DW_OP_GNU_addr_index:
		case DW_OP_GNU_const_index:
			operand1 = dbg->decode(&p, pointer_size);
			break;

		/* Offset size operand. */
		case DW_OP_call_ref:
			operand1 = dbg->decode(&p, offset_size);
			break;

		/*
		 * The first byte is address byte length, followed by
		 * the address value. If the length is 0, the address
		 * size is the same as target pointer size.
		 */
		case DW_OP_GNU_encoded_addr:
			s = *p++;
			if (s == 0)
				s = pointer_size;
			operand1 = dbg->decode(&p, s);
			break;

		/*
		 * Operand1: DIE offset (size depending on DWARF version)
		 * DWARF2: pointer size
		 * DWARF{3,4}: offset size
		 *
		 * Operand2: SLEB128
		 */
		case DW_OP_GNU_implicit_pointer:
			if (version == 2)
				operand1 = dbg->decode(&p, pointer_size);
			else
				operand1 = dbg->decode(&p, offset_size);
			operand2 = _dwarf_decode_sleb128(&p);
			break;

		/*
		 * Operand1: DIE offset (ULEB128)
		 * Operand2: pointer to a block. The block's first byte
		 * is its size.
		 */
		case DW_OP_GNU_const_type:
			operand1 = _dwarf_decode_uleb128(&p);
			operand2 = (Dwarf_Unsigned) (uintptr_t) p;
			s = *p++;
			p += s;
			break;

		/* All other operations cause an error. */
		default:
			count = -1;
			goto done;
		}

		if (lbuf != NULL) {
			lbuf->ld_s[count].lr_number = operand1;
			lbuf->ld_s[count].lr_number2 = operand2;
		}

		count++;
	}

done:
	return (count);
}