Re: Hardware watchpoints

Eli Zaretskii
1999-10-23T03:48:00Z

> What expressions did you try to watch? What chains of values did they
> produce? Which ones are lazy, and which ones aren't?

Thanks for the explanations.

A simple test program is attached at the end of this message. (It's a
program I used for testing several different aspects of watchpoints,
so not everything it includes is relevant to the issue at hand.)

An abridged script of a GDB session follows. As you see, I watched
two different members of a struct variable `foo_var': `foo_var.iv' and
`foo_var.jv'. GDB produced two value chains, each one including the
struct member and the struct itself--all of them marked as lazy.

Perhaps we could use v->type.code in the decision whether to watch any
values but the first one on the value chain?

One question that I still can't figure out is why does GDB at all
_need_ to have the parent struct on the value chain? Where is that
information used?

Also, the v->type member for the parent struct has a NULL type.name
member. Unless I misunderstood gdbtypes.h, it seems to imply that
name should be "struct" or "struct foo".

Here's the GDB session:

e:/src/gnu/gdb-4.18/gdb> gdb gdb.exe
...
(top-gdb) b breakpoint.c:781
Breakpoint 3 at 0x2c61: file breakpoint.c, line 781
(top-gdb) r fptest4
Starting program: e:/src/gnu/gdb-4.18/gdb/gdb.exe fptest4
...
(gdb) b main
Breakpoint 1 at 0x15bf: file fptest.c, line 7
(gdb) r
Starting program: e:/src/gnu/gdb-4.18/gdb/fptest4

Breakpoint 1, main (argv=1, argv=0x911c4) at fptest.c:7
7 volatile double a = M_SQRT2;

(gdb) l 21,24
21 argc = a * a;
22 foo_var.iv = argc + 2;
23 foo_var.jv = argc + 3;
24 if (foo_var.iv < 0)
(gdb) watch foo_var.iv
Hardware watchpoint 2: foo_var.iv
(gdb) watch foo_var.jv
Hardware watchpoint 3: foo_var.jv
(gdb) c
Continuing.

Breakpoint 3, insert_breakpoints () at breakpoint.c:781
781 v = evaluate_expression (b->exp);
(top-gdb) p b->exp_string
$1 = 0x1eabe8 "foo_var.iv"
(top-gdb) p *b->exp
$2 = {language_defn =
During symbol reading, stub type has NULL name.
0xc188, nelts = 9, elts = {{opcode = STRUCTOP_STRUCT, symbol = 0x56,
...}}}
(top-gdb) n
782 value_release_to_mark (mark);
(top-gdb) p *v
$3 = {lval = lval_memory, modifiable = 1, location = {address = 0x90904,
...}, offset = 0, bitsize = 0, bitpos = 0, frame_addr = 0,
type = 0x1e7710, enclosing_type = 0x1e7710, next = 0x1ea6f8,
substring_addr = {memaddr = 0xea890, ...}, regno = -1, lazy = 1 '\001',
optimized_out = 0 '\000', embedded_offset = 0, pointed_to_offset = 0,
bfd_section = 0x0, aligner = {...}}
(top-gdb)p *(struct type *)v->type
$4 = {code = TYPE_CODE_INT, name = 0x1e7754 "int", tag_name = 0x0, length = 4,
upper_bound_type = 0, lower_bound_type = 0, ..., cv_type = 0x1e7710,
flags = 0, nfields = 0, fields = 0x0, ..., type_specific = {
arg_types = 0x0, cplus_stuff = 0x0}}
(top-gdb)p *v->next
$5 = {lval = lval_memory, modifiable = 1, location = {address = 0x90904,
...}, offset = 0, bitsize = 0, bitpos = 0, frame_addr = 0,
type = 0x1e7a3c, enclosing_type = 0x1e7a3c, next = 0x0,
substring_addr = {memaddr = 0xea890, ...}, regno = -1, lazy = 1 '\001',
optimized_out = 0 '\000', embedded_offset = 0, pointed_to_offset = 0,
bfd_section = 0x0, aligner = {...}}
(top-gdb) p *(struct type *)v->next->type
$6 = {code = TYPE_CODE_STRUCT, name = 0x0, tag_name = 0x1ea390 "foo",
length = 20, upper_bound_type = 0, lower_bound_type = 0, ...,
cv_type = 0x1e7a3c, flags = 0, nfields = 5, fields = 0x0x1e7ad4,
vptr_basetype = 0x0, vptr_fieldno = -1, type_specific = {
arg_types = 0x13c120, cplus_stuff = 0x13c120}}
(top-gdb) c
Continuing.

Breakpoint 3, insert_breakpoints () at breakpoint.c:781
781 v = evaluate_expression (b->exp);
(top-gdb) p b->exp_string
$7 = 0x1eabe8 "foo_var.jv"
(top-gdb) n
782 value_release_to_mark (mark);
(top-gdb) p *v
$8 = {lval = lval_memory, modifiable = 1, location = {address = 0x90904,
...}, offset = 16, bitsize = 0, bitpos = 0, frame_addr = 0,
type = 0x1e7710, enclosing_type = 0x1e7710, next = 0x1ea6f8,
substring_addr = {memaddr = 0xea890, ...}, regno = -1, lazy = 1 '\001',
optimized_out = 0 '\000', embedded_offset = 0, pointed_to_offset = 0,
bfd_section = 0x0, aligner = {...}}
(top-gdb)p *(struct type *)v->type
$9 = {code = TYPE_CODE_INT, name = 0x1e7754 "int", tag_name = 0x0, length = 4,
upper_bound_type = 0, lower_bound_type = 0, ..., cv_type = 0x1e7710,
flags = 0, nfields = 0, fields = 0x0, ..., type_specific = {
arg_types = 0x0, cplus_stuff = 0x0}}
(top-gdb)p *v->next
$10 = {lval = lval_memory, modifiable = 1, location = {address = 0x90904,
...}, offset = 0, bitsize = 0, bitpos = 0, frame_addr = 0,
type = 0x1e7a3c, enclosing_type = 0x1e7a3c, next = 0x0,
substring_addr = {memaddr = 0xea890, ...}, regno = -1, lazy = 1 '\001',
optimized_out = 0 '\000', embedded_offset = 0, pointed_to_offset = 0,
bfd_section = 0x0, aligner = {...}}
(top-gdb) p *(struct type *)v->next->type
$11 = {code = TYPE_CODE_STRUCT, name = 0x0, tag_name = 0x1ea390 "foo",
length = 20, upper_bound_type = 0, lower_bound_type = 0, ...,
cv_type = 0x1e7a3c, flags = 0, nfields = 5, fields = 0x0x1e7ad4,
vptr_basetype = 0x0, vptr_fieldno = -1, type_specific = {
arg_types = 0x13c120, cplus_stuff = 0x13c120}}
(top-gdb)

Here's teh source of the test program (the DOS-specific function
getch() reads a single character from the console device in binary
mode):

#include <float.h>
#include <math.h>
#include <stdio.h>

int main (int argc, char *argv[])
{
volatile double a = M_SQRT2;
struct foo {
int iv;
double dv;
unsigned flag1:1;
unsigned flag2:2;
int jv;
} foo_var;

printf ("a squared = %f (should be 2.0)\n", a * a);
a *= argc + 1;
getch ();
printf ("10 log10 (0.5) returns %f (should be -3)\n",
10 * log10 (1.0/(a*a)));
argc = a * a;
foo_var.iv = argc + 2;
foo_var.jv = argc + 3;
if (foo_var.iv < 10)
foo_var.flag1 = 1;
if (foo_var.jv < 100)
foo_var.flag2 = 2;
return 0;
}