diff options
Diffstat (limited to 'rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c')
-rw-r--r-- | rtemstoolkit/elftoolchain/libdwarf/libdwarf_loc.c | 701 |
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); +} |