This is the mail archive of the
gdb@sources.redhat.com
mailing list for the GDB project.
how are debug registers supposed to work?
- From: Ben Johnson <ben at blarg dot net>
- To: gdb at sources dot redhat dot com
- Date: Thu, 28 Aug 2003 17:41:29 -0700
- Subject: how are debug registers supposed to work?
Hi.
I hope this is an acceptable topic for this list. I'm not sure where to
send this question.
I am experimenting with debugging an old (2.0.14?), hacked Linux kernel.
I'm using an old module written by someone at HP that enables remote
debugging of the the kernel over a serial line. This works very well
for the most part. the only bad thing is that data watchpoints don't
work. This bug I'm trying to kill would be relatively easy to find if I
could make watchpoints work.
After researching a little I've ended up thinking that the debug
registers should be able to make this happen. For some reason though I
can't get them to do anything. Well, almost nothing. I can get the cpu
to generate a debug exception when I read the debug registers, which is
not useful.
here's a good reference I've been using:
http://my.tele2.ee/mtx/i386/chp12-02.htm
here's what I'm using to test....
schedule() {
...
static int has_run = 0;
static unsigned long has_run_2 = 1;
if( ! has_run && jiffies > 7000 )
{
has_run = 1;
has_run_2 = 0xffffffff;
asm ("movl %0, %%db0\n"
" movl %1, %%db7\n"
" wbinvd\n"
: /* no output */
:"a"(&has_run_2),
"b"(0x000f0202)
);
/* this should cause an int1 */
has_run_2 = 0;
asm ("wbinvd\n"
" movl %0, %%db7\n"
" wbinvd\n"
: /* no output */
:"b"(0x00030202)
);
/* this should cause an int1 */
has_run_2 = 0xffffffff;
asm ("wbinvd\n"
" movl %0, %%db7\n"
" wbinvd\n"
: /* no output */
:"b"(0x00070202)
);
/* this should cause an int1 */
has_run_2 = 0;
asm ("wbinvd\n"
" movl %0, %%db7\n"
" wbinvd\n"
: /* no output */
:"b"(0x00032202)
);
/* this should cause an int1 */
has_run_2 = 0xffffffff;
asm ("wbinvd\n"
" movl %%db7, %0\n"
" movl %%db0, %1\n"
" movl %%db6, %2\n"
:"=a"(db7), "=b"(addr0), "=c"(db6)
:/* no input */
);
printk(KERN_DEBUG "%s: regs: a0:0x%8.8x "
"db7:0x%8.8x db6:0x%8.8x\n",
__FUNCTION__, addr0, db7, db6);
}
...
}
so, right at the top of the old schedule() function I put some stuff that
messes only once with the debug registers. Here's the gdb output after the cpu
throws a debug exception:
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00112ea8 in schedule () at sched.c:446
446 asm ("wbinvd\n"
(gdb) list
441 );
442
443 /* this should cause an int1 */
444 has_run_2 = 0xffffffff;
445
446 asm ("wbinvd\n"
447 " movl %%db7, %0\n"
448 " movl %%db0, %1\n"
449 " movl %%db6, %2\n"
450 :"=a"(db7), "=b"(addr0), "=c"(db6)
(gdb) info reg
eax 0x192a00 1649152
ecx 0x7 7
edx 0x191d40 1645888
ebx 0x32202 205314
esp 0x1914dc 0x1914dc
ebp 0x191508 0x191508
esi 0x191564 1643876
edi 0x0 0
eip 0x112ea8 0x112ea8
eflags 0x202 514
cs 0x10 16
ss 0x18 24
ds 0x18 24
es 0x18 24
fs 0x2b 43
gs 0x18 24
fctrl 0x0 0
fstat 0x0 0
ftag 0x0 0
fiseg 0x0 0
fioff 0x0 0
foseg 0x0 0
fooff 0x0 0
fop *value not available*
and here's the disassembled code:
112e3e: c7 05 00 2a 19 00 ff movl $0xffffffff,0x192a00 ;--- initial value
112e45: ff ff ff
112e48: b8 00 2a 19 00 mov $0x192a00,%eax ;--- push address into %db0
112e4d: bb 02 02 0f 00 mov $0xf0202,%ebx ;--- LEN0=11, R/W0=11, GE=1, G0=1
112e52: 0f 23 c0 mov %eax,%db0
112e55: 0f 23 fb mov %ebx,%db7
112e58: 0f 09 wbinvd
112e5a: c7 05 00 2a 19 00 00 movl $0x0,0x192a00 ;--- should break here
112e61: 00 00 00
112e64: bb 02 02 03 00 mov $0x30202,%ebx ;--- LEN0=00, R/W0=11, GE=1, G0=1
112e69: 0f 09 wbinvd
112e6b: 0f 23 fb mov %ebx,%db7
112e6e: 0f 09 wbinvd
112e70: c7 05 00 2a 19 00 ff movl $0xffffffff,0x192a00 ;--- should break here
112e77: ff ff ff
112e7a: bb 02 02 07 00 mov $0x70202,%ebx ;--- LEN0=01, R/W0=11, GE=1, G0=1
112e7f: 0f 09 wbinvd
112e81: 0f 23 fb mov %ebx,%db7
112e84: 0f 09 wbinvd
112e86: c7 05 00 2a 19 00 00 movl $0x0,0x192a00 ;--- should break here
112e8d: 00 00 00
112e90: bb 02 22 03 00 mov $0x32202,%ebx ;--- LEN0=00, R/W0=11, GD=1, GE=1, G0=1 /* GD=1 means watch for debug reg access. */
112e95: 0f 09 wbinvd
112e97: 0f 23 fb mov %ebx,%db7
112e9a: 0f 09 wbinvd
112e9c: c7 05 00 2a 19 00 ff movl $0xffffffff,0x192a00 ;--- should break here
112ea3: ff ff ff
112ea6: 0f 09 wbinvd
112ea8: 0f 21 f8 mov %db7,%eax ;--- break!!!! debug reg is accessed.
112eab: 0f 21 c3 mov %db0,%ebx
112eae: 0f 21 f1 mov %db6,%ecx
112eb1: 89 c2 mov %eax,%edx
112eb3: 89 de mov %ebx,%esi
112eb5: 51 push %ecx
112eb6: 52 push %edx
112eb7: 56 push %esi
112eb8: 68 b2 36 18 00 push $0x1836b2
112ebd: 68 bb 36 18 00 push $0x1836bb
112ec2: e8 4d 27 00 00 call 115614 <printk>
########################################################################
So, the CPU is generating a debug exception, and I am catching it. it's
just not happening when I want or expect it to happen. The same thing
happens for program instruction fetches. It doesn't break.
I stuck in all the wbinvd instructions thinking it might be a cache
issue. I have yet to turn the cache off. it seems to me though that I
should be getting some exception with or without the cache enabled.
What am I doing wrong? anyone know? who knows how to use these
registers?
Thanks a million,
- Ben Johnson