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