summaryrefslogtreecommitdiffstats
path: root/rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c
diff options
context:
space:
mode:
Diffstat (limited to 'rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c')
-rw-r--r--rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c701
1 files changed, 701 insertions, 0 deletions
diff --git a/rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c b/rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c
new file mode 100644
index 0000000..c2d3f5c
--- /dev/null
+++ b/rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c
@@ -0,0 +1,701 @@
+/*-
+ * Copyright (c) 2007 John Birrell (jb@freebsd.org)
+ * Copyright (c) 2014 Kai Wang
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "_libdwarf.h"
+
+ELFTC_VCSID("$Id: libdwarf_loc.c 3070 2014-06-23 03:08:33Z kaiwang27 $");
+
+/*
+ * 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);
+}
+
+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);
+}
+
+int
+_dwarf_loc_fill_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *llbuf, uint8_t *in,
+ uint64_t in_len, uint8_t pointer_size, uint8_t offset_size,
+ uint8_t version, Dwarf_Error *error)
+{
+ int num;
+
+ assert(llbuf != NULL);
+ assert(in != NULL);
+ assert(in_len > 0);
+
+ /* Compute the number of locations. */
+ if ((num = _dwarf_loc_fill_loc(dbg, NULL, pointer_size, offset_size,
+ version, in, in_len)) < 0) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_LOC_EXPR_BAD);
+ return (DW_DLE_LOC_EXPR_BAD);
+ }
+
+ llbuf->ld_cents = num;
+ if (num <= 0)
+ return (DW_DLE_NONE);
+
+ if ((llbuf->ld_s = calloc(num, sizeof(Dwarf_Loc))) == NULL) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+
+ (void) _dwarf_loc_fill_loc(dbg, llbuf, pointer_size, offset_size,
+ version, in, in_len);
+
+ return (DW_DLE_NONE);
+}
+
+int
+_dwarf_loc_fill_locexpr(Dwarf_Debug dbg, Dwarf_Locdesc **ret_llbuf, uint8_t *in,
+ uint64_t in_len, uint8_t pointer_size, uint8_t offset_size,
+ uint8_t version, Dwarf_Error *error)
+{
+ Dwarf_Locdesc *llbuf;
+ int ret;
+
+ if ((llbuf = malloc(sizeof(Dwarf_Locdesc))) == NULL) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+ llbuf->ld_lopc = 0;
+ llbuf->ld_hipc = ~0ULL;
+ llbuf->ld_s = NULL;
+
+ ret = _dwarf_loc_fill_locdesc(dbg, llbuf, in, in_len, pointer_size,
+ offset_size, version, error);
+ if (ret != DW_DLE_NONE) {
+ free(llbuf);
+ return (ret);
+ }
+
+ *ret_llbuf = llbuf;
+
+ return (ret);
+}
+
+int
+_dwarf_loc_add(Dwarf_Die die, Dwarf_Attribute at, Dwarf_Error *error)
+{
+ Dwarf_Debug dbg;
+ Dwarf_CU cu;
+ int ret;
+
+ assert(at->at_ld == NULL);
+ assert(at->u[1].u8p != NULL);
+ assert(at->u[0].u64 > 0);
+
+ cu = die->die_cu;
+ assert(cu != NULL);
+
+ dbg = cu->cu_dbg;
+ assert(dbg != NULL);
+
+ ret = _dwarf_loc_fill_locexpr(dbg, &at->at_ld, at->u[1].u8p,
+ at->u[0].u64, cu->cu_pointer_size, cu->cu_length_size == 4 ? 4 : 8,
+ cu->cu_version, error);
+
+ return (ret);
+}