Convert the unavailable vector to be bit, not byte, based.
https://sourceware.org/ml/gdb-patches/2013-12/msg00144.html The vector of unavailable parts of a value is currently byte based. Given that we can model a value down to the bit level, we can potentially loose information with the current implementation. After this patch we model the unavailable information in bits. gdb/ChangeLog * dwarf2loc.c (read_pieced_value): Mark bits, not bytes unavailable, use correct bit length. * value.c (struct value): Extend comment on unavailable to indicate that it is bit based. (value_bits_available): New function. (value_bytes_available): Call value_bits_available. (value_entirely_available): Check against the bit length, not byte length. (mark_value_bits_unavailable): New function. (mark_value_bytes_unavailable): Move contents to mark_value_bits_unavailable, call to same. (memcmp_with_bit_offsets): New function. (value_available_contents_bits_eq): New function, takes the functionality from value_available_contents_eq but uses memcmp_with_bit_offsets now, and is bit not byte based. (value_available_contents_eq): Move implementation into value_available_contents_bits_eq, call to same. (value_contents_copy_raw): Work on bits, not bytes. (unpack_value_bits_as_long_1): Check availability in bits, not bytes. * value.h (value_bits_available): Declare new function. (mark_value_bits_unavailable): Declare new function. gdb/testsuite/ChangeLog * gdb.trace/unavailable-dwarf-piece.c: New file. * gdb.trace/unavailable-dwarf-piece.exp: New file.
This commit is contained in:
parent
4a357820ad
commit
bdf2220615
|
@ -1,3 +1,28 @@
|
|||
2013-12-17 Andrew Burgess <aburgess@broadcom.com>
|
||||
|
||||
* dwarf2loc.c (read_pieced_value): Mark bits, not bytes
|
||||
unavailable, use correct bit length.
|
||||
* value.c (struct value): Extend comment on unavailable to
|
||||
indicate that it is bit based.
|
||||
(value_bits_available): New function.
|
||||
(value_bytes_available): Call value_bits_available.
|
||||
(value_entirely_available): Check against the bit length, not byte
|
||||
length.
|
||||
(mark_value_bits_unavailable): New function.
|
||||
(mark_value_bytes_unavailable): Move contents to
|
||||
mark_value_bits_unavailable, call to same.
|
||||
(memcmp_with_bit_offsets): New function.
|
||||
(value_available_contents_bits_eq): New function, takes the
|
||||
functionality from value_available_contents_eq but uses
|
||||
memcmp_with_bit_offsets now, and is bit not byte based.
|
||||
(value_available_contents_eq): Move implementation into
|
||||
value_available_contents_bits_eq, call to same.
|
||||
(value_contents_copy_raw): Work on bits, not bytes.
|
||||
(unpack_value_bits_as_long_1): Check availability in bits, not
|
||||
bytes.
|
||||
* value.h (value_bits_available): Declare new function.
|
||||
(mark_value_bits_unavailable): Declare new function.
|
||||
|
||||
2013-12-16 Pierre Muller <muller@sourceware.org>
|
||||
|
||||
Fix compilation error for cygwin native build.
|
||||
|
|
|
@ -1709,7 +1709,7 @@ read_pieced_value (struct value *v)
|
|||
if (optim)
|
||||
set_value_optimized_out (v, 1);
|
||||
if (unavail)
|
||||
mark_value_bytes_unavailable (v, offset, this_size);
|
||||
mark_value_bits_unavailable (v, offset, this_size_bits);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2013-12-17 Andrew Burgess <aburgess@broadcom.com>
|
||||
|
||||
* gdb.trace/unavailable-dwarf-piece.c: New file.
|
||||
* gdb.trace/unavailable-dwarf-piece.exp: New file.
|
||||
|
||||
2013-12-15 Yao Qi <yao@codesourcery.com>
|
||||
|
||||
* gdb.perf/skip-prologue.c: New.
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2013 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
struct s
|
||||
{
|
||||
unsigned char a;
|
||||
unsigned char b;
|
||||
unsigned char c;
|
||||
};
|
||||
|
||||
struct t
|
||||
{
|
||||
/* First, a complete byte. */
|
||||
unsigned char a;
|
||||
/* Next, 8 single bits. */
|
||||
unsigned char b : 1;
|
||||
unsigned char c : 1;
|
||||
unsigned char d : 1;
|
||||
unsigned char e : 1;
|
||||
unsigned char f : 1;
|
||||
unsigned char g : 1;
|
||||
unsigned char h : 1;
|
||||
unsigned char i : 1;
|
||||
/* Now another byte. */
|
||||
unsigned char j;
|
||||
};
|
||||
|
||||
void
|
||||
end (void)
|
||||
{
|
||||
/* Nothing. */
|
||||
}
|
||||
|
||||
void
|
||||
dummy (void)
|
||||
{
|
||||
/* Nothing. */
|
||||
}
|
||||
|
||||
int
|
||||
foo (struct s x, struct s y, struct s z)
|
||||
{
|
||||
dummy ();
|
||||
asm (".global foo_end_lbl\nfoo_end_lbl:");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bar (struct t x, struct t y, struct t z)
|
||||
{
|
||||
dummy ();
|
||||
asm (".global bar_end_lbl\nbar_end_lbl:");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
struct s v = { 0, 1, 2 };
|
||||
struct t w = { 5, 0, 1, 0, 1, 0, 1, 0, 1, 7 };
|
||||
int ans;
|
||||
|
||||
ans = foo (v, v, v);
|
||||
|
||||
end ();
|
||||
|
||||
ans = bar (w, w, w);
|
||||
|
||||
end ();
|
||||
|
||||
return ans;
|
||||
}
|
|
@ -0,0 +1,334 @@
|
|||
# Copyright (C) 2013 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
load_lib "trace-support.exp"
|
||||
load_lib dwarf.exp
|
||||
|
||||
if {![dwarf2_support]} {
|
||||
return 0
|
||||
}
|
||||
|
||||
standard_testfile .c
|
||||
|
||||
set asm_file "${testfile}-dbg.s"
|
||||
set opts {}
|
||||
|
||||
if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \
|
||||
object {nodebug}] != "" } {
|
||||
return -1
|
||||
}
|
||||
|
||||
Dwarf::assemble $asm_file {
|
||||
declare_labels uchar_label struct_s_label foo_label struct_t_label bar_label
|
||||
|
||||
cu {} {
|
||||
compile_unit {{language @DW_LANG_C}} {
|
||||
uchar_label: DW_TAG_base_type {
|
||||
{name "unsigned char"}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{encoding @DW_ATE_unsigned_char}
|
||||
}
|
||||
|
||||
struct_s_label: DW_TAG_structure_type {
|
||||
{name s}
|
||||
{byte_size 3 DW_FORM_sdata}
|
||||
{decl_file 1}
|
||||
{decl_line 1}
|
||||
} {
|
||||
DW_TAG_member {
|
||||
{name a}
|
||||
{type :$uchar_label}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 0
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name b}
|
||||
{type :$uchar_label}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name c}
|
||||
{type :$uchar_label}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 2
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
}
|
||||
|
||||
struct_t_label: DW_TAG_structure_type {
|
||||
{name t}
|
||||
{byte_size 3 DW_FORM_sdata}
|
||||
{decl_file 1}
|
||||
{decl_line 1}
|
||||
} {
|
||||
DW_TAG_member {
|
||||
{name a}
|
||||
{type :$uchar_label}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 0
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name b}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 7 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name c}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 6 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name d}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 5 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name e}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 4 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name f}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 3 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name g}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 2 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name h}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 1 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name i}
|
||||
{type :$uchar_label}
|
||||
{byte_size 1 DW_FORM_sdata}
|
||||
{bit_size 1 DW_FORM_sdata}
|
||||
{bit_offset 0 DW_FORM_sdata}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_member {
|
||||
{name j}
|
||||
{type :$uchar_label}
|
||||
{data_member_location {
|
||||
DW_OP_plus_uconst 2
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
}
|
||||
|
||||
DW_TAG_subprogram {
|
||||
{name foo}
|
||||
{decl_file 1}
|
||||
{low_pc foo addr}
|
||||
{high_pc foo_end_lbl addr}
|
||||
} {
|
||||
DW_TAG_formal_parameter {
|
||||
{type :$struct_s_label}
|
||||
{name x}
|
||||
{location {
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 2
|
||||
DW_OP_reg0
|
||||
DW_OP_piece 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_formal_parameter {
|
||||
{type :$struct_s_label}
|
||||
{name y}
|
||||
{location {
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
DW_OP_reg0
|
||||
DW_OP_piece 1
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_formal_parameter {
|
||||
{type :$struct_s_label}
|
||||
{name z}
|
||||
{location {
|
||||
DW_OP_reg0
|
||||
DW_OP_piece 1
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 2
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DW_TAG_subprogram {
|
||||
{name bar}
|
||||
{decl_file 1}
|
||||
{low_pc bar addr}
|
||||
{high_pc bar_end_lbl addr}
|
||||
} {
|
||||
DW_TAG_formal_parameter {
|
||||
{type :$struct_t_label}
|
||||
{name x}
|
||||
{location {
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
DW_OP_reg0
|
||||
DW_OP_bit_piece 1 0
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_bit_piece 7 0
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_formal_parameter {
|
||||
{type :$struct_t_label}
|
||||
{name y}
|
||||
{location {
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_bit_piece 3 0
|
||||
DW_OP_reg0
|
||||
DW_OP_bit_piece 1 0
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_bit_piece 4 0
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
DW_TAG_formal_parameter {
|
||||
{type :$struct_t_label}
|
||||
{name z}
|
||||
{location {
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_bit_piece 7 0
|
||||
DW_OP_reg0
|
||||
DW_OP_bit_piece 1 0
|
||||
DW_OP_lit0
|
||||
DW_OP_stack_value
|
||||
DW_OP_piece 1
|
||||
} SPECIAL_expr}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if { [gdb_compile ${asm_file} ${binfile}2.o object {nodebug}] != "" } {
|
||||
return -1
|
||||
}
|
||||
|
||||
if { [gdb_compile [list ${binfile}1.o ${binfile}2.o] ${binfile} \
|
||||
executable {}] != "" } {
|
||||
return -1
|
||||
}
|
||||
|
||||
clean_restart ${testfile}
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
if ![gdb_target_supports_trace] {
|
||||
unsupported "target does not support trace"
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_breakpoint "end"
|
||||
|
||||
with_test_prefix "tracing foo" {
|
||||
gdb_test "trace foo" ".*"
|
||||
gdb_test_no_output "tstart"
|
||||
gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*"
|
||||
gdb_test_no_output "tstop"
|
||||
|
||||
gdb_test "tfind 0" "Found trace frame 0, tracepoint .*"
|
||||
gdb_test "p/d x" "\\\$${decimal} = {a = 0, b = 0, c = <unavailable>}"
|
||||
gdb_test "p/d y" "\\\$${decimal} = {a = 0, b = <unavailable>, c = 0}"
|
||||
gdb_test "p/d z" "\\\$${decimal} = {a = <unavailable>, b = 0, c = 0}"
|
||||
|
||||
gdb_test "tfind none" "No longer looking at any trace frame.*"
|
||||
}
|
||||
|
||||
with_test_prefix "tracing bar" {
|
||||
gdb_test "trace bar" ".*"
|
||||
gdb_test_no_output "tstart"
|
||||
gdb_test "continue" "Continuing\\.\[ \r\n\]+Breakpoint.*"
|
||||
gdb_test_no_output "tstop"
|
||||
|
||||
gdb_test "tfind 0" "Found trace frame 0, tracepoint .*"
|
||||
gdb_test "p/d x" "\\\$${decimal} = {a = 0, b = <unavailable>, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, i = 0, j = 0}"
|
||||
gdb_test "p/d y" "\\\$${decimal} = {a = 0, b = 0, c = 0, d = 0, e = <unavailable>, f = 0, g = 0, h = 0, i = 0, j = 0}"
|
||||
gdb_test "p/d z" "\\\$${decimal} = {a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, i = <unavailable>, j = 0}"
|
||||
|
||||
gdb_test "tfind none" "No longer looking at any trace frame.*"
|
||||
}
|
181
gdb/value.c
181
gdb/value.c
|
@ -333,18 +333,27 @@ struct value
|
|||
|
||||
/* Unavailable ranges in CONTENTS. We mark unavailable ranges,
|
||||
rather than available, since the common and default case is for a
|
||||
value to be available. This is filled in at value read time. */
|
||||
value to be available. This is filled in at value read time. The
|
||||
unavailable ranges are tracked in bits. */
|
||||
VEC(range_s) *unavailable;
|
||||
};
|
||||
|
||||
int
|
||||
value_bytes_available (const struct value *value, int offset, int length)
|
||||
value_bits_available (const struct value *value, int offset, int length)
|
||||
{
|
||||
gdb_assert (!value->lazy);
|
||||
|
||||
return !ranges_contain (value->unavailable, offset, length);
|
||||
}
|
||||
|
||||
int
|
||||
value_bytes_available (const struct value *value, int offset, int length)
|
||||
{
|
||||
return value_bits_available (value,
|
||||
offset * TARGET_CHAR_BIT,
|
||||
length * TARGET_CHAR_BIT);
|
||||
}
|
||||
|
||||
int
|
||||
value_entirely_available (struct value *value)
|
||||
{
|
||||
|
@ -371,7 +380,8 @@ value_entirely_unavailable (struct value *value)
|
|||
struct range *t = VEC_index (range_s, value->unavailable, 0);
|
||||
|
||||
if (t->offset == 0
|
||||
&& t->length == TYPE_LENGTH (value_enclosing_type (value)))
|
||||
&& t->length == (TARGET_CHAR_BIT *
|
||||
TYPE_LENGTH (value_enclosing_type (value))))
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -379,7 +389,7 @@ value_entirely_unavailable (struct value *value)
|
|||
}
|
||||
|
||||
void
|
||||
mark_value_bytes_unavailable (struct value *value, int offset, int length)
|
||||
mark_value_bits_unavailable (struct value *value, int offset, int length)
|
||||
{
|
||||
range_s newr;
|
||||
int i;
|
||||
|
@ -543,6 +553,14 @@ mark_value_bytes_unavailable (struct value *value, int offset, int length)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
mark_value_bytes_unavailable (struct value *value, int offset, int length)
|
||||
{
|
||||
mark_value_bits_unavailable (value,
|
||||
offset * TARGET_CHAR_BIT,
|
||||
length * TARGET_CHAR_BIT);
|
||||
}
|
||||
|
||||
/* Find the first range in RANGES that overlaps the range defined by
|
||||
OFFSET and LENGTH, starting at element POS in the RANGES vector,
|
||||
Returns the index into RANGES where such overlapping range was
|
||||
|
@ -562,10 +580,118 @@ find_first_range_overlap (VEC(range_s) *ranges, int pos,
|
|||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
value_available_contents_eq (const struct value *val1, int offset1,
|
||||
const struct value *val2, int offset2,
|
||||
int length)
|
||||
/* Compare LENGTH_BITS of memory at PTR1 + OFFSET1_BITS with the memory at
|
||||
PTR2 + OFFSET2_BITS. Return 0 if the memory is the same, otherwise
|
||||
return non-zero.
|
||||
|
||||
It must always be the case that:
|
||||
OFFSET1_BITS % TARGET_CHAR_BIT == OFFSET2_BITS % TARGET_CHAR_BIT
|
||||
|
||||
It is assumed that memory can be accessed from:
|
||||
PTR + (OFFSET_BITS / TARGET_CHAR_BIT)
|
||||
to:
|
||||
PTR + ((OFFSET_BITS + LENGTH_BITS + TARGET_CHAR_BIT - 1)
|
||||
/ TARGET_CHAR_BIT) */
|
||||
static int
|
||||
memcmp_with_bit_offsets (const gdb_byte *ptr1, size_t offset1_bits,
|
||||
const gdb_byte *ptr2, size_t offset2_bits,
|
||||
size_t length_bits)
|
||||
{
|
||||
gdb_assert (offset1_bits % TARGET_CHAR_BIT
|
||||
== offset2_bits % TARGET_CHAR_BIT);
|
||||
|
||||
if (offset1_bits % TARGET_CHAR_BIT != 0)
|
||||
{
|
||||
size_t bits;
|
||||
gdb_byte mask, b1, b2;
|
||||
|
||||
/* The offset from the base pointers PTR1 and PTR2 is not a complete
|
||||
number of bytes. A number of bits up to either the next exact
|
||||
byte boundary, or LENGTH_BITS (which ever is sooner) will be
|
||||
compared. */
|
||||
bits = TARGET_CHAR_BIT - offset1_bits % TARGET_CHAR_BIT;
|
||||
gdb_assert (bits < sizeof (mask) * TARGET_CHAR_BIT);
|
||||
mask = (1 << bits) - 1;
|
||||
|
||||
if (length_bits < bits)
|
||||
{
|
||||
mask &= ~(gdb_byte) ((1 << (bits - length_bits)) - 1);
|
||||
bits = length_bits;
|
||||
}
|
||||
|
||||
/* Now load the two bytes and mask off the bits we care about. */
|
||||
b1 = *(ptr1 + offset1_bits / TARGET_CHAR_BIT) & mask;
|
||||
b2 = *(ptr2 + offset2_bits / TARGET_CHAR_BIT) & mask;
|
||||
|
||||
if (b1 != b2)
|
||||
return 1;
|
||||
|
||||
/* Now update the length and offsets to take account of the bits
|
||||
we've just compared. */
|
||||
length_bits -= bits;
|
||||
offset1_bits += bits;
|
||||
offset2_bits += bits;
|
||||
}
|
||||
|
||||
if (length_bits % TARGET_CHAR_BIT != 0)
|
||||
{
|
||||
size_t bits;
|
||||
size_t o1, o2;
|
||||
gdb_byte mask, b1, b2;
|
||||
|
||||
/* The length is not an exact number of bytes. After the previous
|
||||
IF.. block then the offsets are byte aligned, or the
|
||||
length is zero (in which case this code is not reached). Compare
|
||||
a number of bits at the end of the region, starting from an exact
|
||||
byte boundary. */
|
||||
bits = length_bits % TARGET_CHAR_BIT;
|
||||
o1 = offset1_bits + length_bits - bits;
|
||||
o2 = offset2_bits + length_bits - bits;
|
||||
|
||||
gdb_assert (bits < sizeof (mask) * TARGET_CHAR_BIT);
|
||||
mask = ((1 << bits) - 1) << (TARGET_CHAR_BIT - bits);
|
||||
|
||||
gdb_assert (o1 % TARGET_CHAR_BIT == 0);
|
||||
gdb_assert (o2 % TARGET_CHAR_BIT == 0);
|
||||
|
||||
b1 = *(ptr1 + o1 / TARGET_CHAR_BIT) & mask;
|
||||
b2 = *(ptr2 + o2 / TARGET_CHAR_BIT) & mask;
|
||||
|
||||
if (b1 != b2)
|
||||
return 1;
|
||||
|
||||
length_bits -= bits;
|
||||
}
|
||||
|
||||
if (length_bits > 0)
|
||||
{
|
||||
/* We've now taken care of any stray "bits" at the start, or end of
|
||||
the region to compare, the remainder can be covered with a simple
|
||||
memcmp. */
|
||||
gdb_assert (offset1_bits % TARGET_CHAR_BIT == 0);
|
||||
gdb_assert (offset2_bits % TARGET_CHAR_BIT == 0);
|
||||
gdb_assert (length_bits % TARGET_CHAR_BIT == 0);
|
||||
|
||||
return memcmp (ptr1 + offset1_bits / TARGET_CHAR_BIT,
|
||||
ptr2 + offset2_bits / TARGET_CHAR_BIT,
|
||||
length_bits / TARGET_CHAR_BIT);
|
||||
}
|
||||
|
||||
/* Length is zero, regions match. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Helper function for value_available_contents_eq. The only difference is
|
||||
that this function is bit rather than byte based.
|
||||
|
||||
Compare LENGTH bits of VAL1's contents starting at OFFSET1 bits with
|
||||
LENGTH bits of VAL2's contents starting at OFFSET2 bits. Return true
|
||||
if the available bits match. */
|
||||
|
||||
static int
|
||||
value_available_contents_bits_eq (const struct value *val1, int offset1,
|
||||
const struct value *val2, int offset2,
|
||||
int length)
|
||||
{
|
||||
int idx1 = 0, idx2 = 0;
|
||||
|
||||
|
@ -585,9 +711,9 @@ value_available_contents_eq (const struct value *val1, int offset1,
|
|||
|
||||
/* The usual case is for both values to be completely available. */
|
||||
if (idx1 == -1 && idx2 == -1)
|
||||
return (memcmp (val1->contents + offset1,
|
||||
val2->contents + offset2,
|
||||
length) == 0);
|
||||
return (memcmp_with_bit_offsets (val1->contents, offset1,
|
||||
val2->contents, offset2,
|
||||
length) == 0);
|
||||
/* The contents only match equal if the available set matches as
|
||||
well. */
|
||||
else if (idx1 == -1 || idx2 == -1)
|
||||
|
@ -620,9 +746,8 @@ value_available_contents_eq (const struct value *val1, int offset1,
|
|||
return 0;
|
||||
|
||||
/* Compare the _available_ contents. */
|
||||
if (memcmp (val1->contents + offset1,
|
||||
val2->contents + offset2,
|
||||
l1) != 0)
|
||||
if (memcmp_with_bit_offsets (val1->contents, offset1,
|
||||
val2->contents, offset2, l1) != 0)
|
||||
return 0;
|
||||
|
||||
length -= h1;
|
||||
|
@ -633,6 +758,16 @@ value_available_contents_eq (const struct value *val1, int offset1,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
value_available_contents_eq (const struct value *val1, int offset1,
|
||||
const struct value *val2, int offset2,
|
||||
int length)
|
||||
{
|
||||
return value_available_contents_bits_eq (val1, offset1 * TARGET_CHAR_BIT,
|
||||
val2, offset2 * TARGET_CHAR_BIT,
|
||||
length * TARGET_CHAR_BIT);
|
||||
}
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
|
||||
static void show_values (char *, int);
|
||||
|
@ -972,6 +1107,7 @@ value_contents_copy_raw (struct value *dst, int dst_offset,
|
|||
{
|
||||
range_s *r;
|
||||
int i;
|
||||
int src_bit_offset, dst_bit_offset, bit_length;
|
||||
|
||||
/* A lazy DST would make that this copy operation useless, since as
|
||||
soon as DST's contents were un-lazied (by a later value_contents
|
||||
|
@ -990,17 +1126,20 @@ value_contents_copy_raw (struct value *dst, int dst_offset,
|
|||
length);
|
||||
|
||||
/* Copy the meta-data, adjusted. */
|
||||
src_bit_offset = src_offset * TARGET_CHAR_BIT;
|
||||
dst_bit_offset = dst_offset * TARGET_CHAR_BIT;
|
||||
bit_length = length * TARGET_CHAR_BIT;
|
||||
for (i = 0; VEC_iterate (range_s, src->unavailable, i, r); i++)
|
||||
{
|
||||
ULONGEST h, l;
|
||||
|
||||
l = max (r->offset, src_offset);
|
||||
h = min (r->offset + r->length, src_offset + length);
|
||||
l = max (r->offset, src_bit_offset);
|
||||
h = min (r->offset + r->length, src_bit_offset + bit_length);
|
||||
|
||||
if (l < h)
|
||||
mark_value_bytes_unavailable (dst,
|
||||
dst_offset + (l - src_offset),
|
||||
h - l);
|
||||
mark_value_bits_unavailable (dst,
|
||||
dst_bit_offset + (l - src_bit_offset),
|
||||
h - l);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2884,8 +3023,8 @@ unpack_value_bits_as_long_1 (struct type *field_type, const gdb_byte *valaddr,
|
|||
read_offset = bitpos / 8;
|
||||
|
||||
if (original_value != NULL
|
||||
&& !value_bytes_available (original_value, embedded_offset + read_offset,
|
||||
bytes_read))
|
||||
&& !value_bits_available (original_value, embedded_offset + bitpos,
|
||||
bitsize))
|
||||
return 0;
|
||||
|
||||
val = extract_unsigned_integer (valaddr + embedded_offset + read_offset,
|
||||
|
|
14
gdb/value.h
14
gdb/value.h
|
@ -436,6 +436,14 @@ extern int value_bits_synthetic_pointer (const struct value *value,
|
|||
extern int value_bytes_available (const struct value *value,
|
||||
int offset, int length);
|
||||
|
||||
/* Given a value, determine whether the contents bits starting at
|
||||
OFFSET and extending for LENGTH bits are available. This returns
|
||||
nonzero if all bits in the given range are available, zero if any
|
||||
bit is unavailable. */
|
||||
|
||||
extern int value_bits_available (const struct value *value,
|
||||
int offset, int length);
|
||||
|
||||
/* Like value_bytes_available, but return false if any byte in the
|
||||
whole object is unavailable. */
|
||||
extern int value_entirely_available (struct value *value);
|
||||
|
@ -450,6 +458,12 @@ extern int value_entirely_unavailable (struct value *value);
|
|||
extern void mark_value_bytes_unavailable (struct value *value,
|
||||
int offset, int length);
|
||||
|
||||
/* Mark VALUE's content bits starting at OFFSET and extending for
|
||||
LENGTH bits as unavailable. */
|
||||
|
||||
extern void mark_value_bits_unavailable (struct value *value,
|
||||
int offset, int length);
|
||||
|
||||
/* Compare LENGTH bytes of VAL1's contents starting at OFFSET1 with
|
||||
LENGTH bytes of VAL2's contents starting at OFFSET2.
|
||||
|
||||
|
|
Loading…
Reference in New Issue