aboutsummaryrefslogtreecommitdiff
path: root/contrib/elftoolchain/libdwarf/libdwarf_loc.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/elftoolchain/libdwarf/libdwarf_loc.c')
-rw-r--r--contrib/elftoolchain/libdwarf/libdwarf_loc.c108
1 files changed, 84 insertions, 24 deletions
diff --git a/contrib/elftoolchain/libdwarf/libdwarf_loc.c b/contrib/elftoolchain/libdwarf/libdwarf_loc.c
index ea366fb0768e..c2d3f5cc6662 100644
--- a/contrib/elftoolchain/libdwarf/libdwarf_loc.c
+++ b/contrib/elftoolchain/libdwarf/libdwarf_loc.c
@@ -1,5 +1,6 @@
/*-
* 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
@@ -26,7 +27,7 @@
#include "_libdwarf.h"
-ELFTC_VCSID("$Id: libdwarf_loc.c 2070 2011-10-27 03:05:32Z jkoshy $");
+ELFTC_VCSID("$Id: libdwarf_loc.c 3070 2014-06-23 03:08:33Z kaiwang27 $");
/*
* Given an array of bytes of length 'len' representing a
@@ -38,12 +39,12 @@ ELFTC_VCSID("$Id: libdwarf_loc.c 2070 2011-10-27 03:05:32Z jkoshy $");
*/
static int
_dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
- uint8_t *p, int len)
+ uint8_t offset_size, uint8_t version, uint8_t *p, int len)
{
int count;
uint64_t operand1;
uint64_t operand2;
- uint8_t *ps, *pe;
+ uint8_t *ps, *pe, s;
count = 0;
ps = p;
@@ -165,37 +166,49 @@ _dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
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_const1s:
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_const2s:
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_const4s:
+ 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:
@@ -207,6 +220,9 @@ _dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
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;
@@ -252,6 +268,7 @@ _dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
* 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;
@@ -267,10 +284,14 @@ _dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
/*
* Operation with an unsigned LEB128 operand
- * followed by a block. Store a pointer to the
- * block in the operand2.
+ * 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;
@@ -278,25 +299,59 @@ _dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
/* 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;
+
/*
- * 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
+ * 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_call_ref:
- operand1 = dbg->decode(&p, dbg->dbg_offset_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;
- break;
+ goto done;
}
if (lbuf != NULL) {
@@ -307,6 +362,7 @@ _dwarf_loc_fill_loc(Dwarf_Debug dbg, Dwarf_Locdesc *lbuf, uint8_t pointer_size,
count++;
}
+done:
return (count);
}
@@ -561,7 +617,8 @@ _dwarf_loc_expr_add_atom(Dwarf_Debug dbg, uint8_t *out, uint8_t *end,
int
_dwarf_loc_fill_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *llbuf, uint8_t *in,
- uint64_t in_len, uint8_t pointer_size, Dwarf_Error *error)
+ uint64_t in_len, uint8_t pointer_size, uint8_t offset_size,
+ uint8_t version, Dwarf_Error *error)
{
int num;
@@ -570,8 +627,8 @@ _dwarf_loc_fill_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *llbuf, uint8_t *in,
assert(in_len > 0);
/* Compute the number of locations. */
- if ((num = _dwarf_loc_fill_loc(dbg, NULL, pointer_size, in, in_len)) <
- 0) {
+ 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);
}
@@ -585,14 +642,16 @@ _dwarf_loc_fill_locdesc(Dwarf_Debug dbg, Dwarf_Locdesc *llbuf, uint8_t *in,
return (DW_DLE_MEMORY);
}
- (void) _dwarf_loc_fill_loc(dbg, llbuf, pointer_size, in, in_len);
+ (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, Dwarf_Error *error)
+ uint64_t in_len, uint8_t pointer_size, uint8_t offset_size,
+ uint8_t version, Dwarf_Error *error)
{
Dwarf_Locdesc *llbuf;
int ret;
@@ -606,7 +665,7 @@ _dwarf_loc_fill_locexpr(Dwarf_Debug dbg, Dwarf_Locdesc **ret_llbuf, uint8_t *in,
llbuf->ld_s = NULL;
ret = _dwarf_loc_fill_locdesc(dbg, llbuf, in, in_len, pointer_size,
- error);
+ offset_size, version, error);
if (ret != DW_DLE_NONE) {
free(llbuf);
return (ret);
@@ -635,7 +694,8 @@ _dwarf_loc_add(Dwarf_Die die, Dwarf_Attribute at, Dwarf_Error *error)
assert(dbg != NULL);
ret = _dwarf_loc_fill_locexpr(dbg, &at->at_ld, at->u[1].u8p,
- at->u[0].u64, cu->cu_pointer_size, error);
+ at->u[0].u64, cu->cu_pointer_size, cu->cu_length_size == 4 ? 4 : 8,
+ cu->cu_version, error);
return (ret);
}