* how are debug registers supposed to work?
@ 2003-08-29 0:41 Ben Johnson
2003-09-03 22:55 ` Andrew Cagney
2003-09-17 0:30 ` Ben Johnson
0 siblings, 2 replies; 4+ messages in thread
From: Ben Johnson @ 2003-08-29 0:41 UTC (permalink / raw)
To: gdb
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
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: how are debug registers supposed to work?
2003-08-29 0:41 how are debug registers supposed to work? Ben Johnson
@ 2003-09-03 22:55 ` Andrew Cagney
2003-09-04 0:17 ` Ben Johnson
2003-09-17 0:30 ` Ben Johnson
1 sibling, 1 reply; 4+ messages in thread
From: Andrew Cagney @ 2003-09-03 22:55 UTC (permalink / raw)
To: Ben Johnson; +Cc: gdb
> 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?
Just a thought, you're not fighting a user space process playing with
those registers?
The other is to look at GDB using hardware debug registers on a user
process.
Andrew
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: how are debug registers supposed to work?
2003-09-03 22:55 ` Andrew Cagney
@ 2003-09-04 0:17 ` Ben Johnson
0 siblings, 0 replies; 4+ messages in thread
From: Ben Johnson @ 2003-09-04 0:17 UTC (permalink / raw)
To: Andrew Cagney; +Cc: gdb
Thanks for the response.
Everything on this box is carefully (as possible) controlled. I have
removed all reference to the debug registers throughout the kernel. (I
don't know if they can be accessed directly from user space, but I would
guess not.)
I've turned on the 'GD' bit in %db7. That causes a debug exception
(int1) to be thrown when any of the debug registers are accessed or
written to. I believe they're not be fooled with because, unless I
purposefully read or write to the debug regs now, I never get a debug
exception.
I've tried setting both code and data break/watchpoints, and none of
them seem to work at all. I know the interrupt handler is setup
correctly because I do get the interrupt when the GD bit is set and I
try to read %db7. I've found no other way to make these register do
anything though. I've given up. I think they just don't work.
but, how could they not work? There *must* be something I'm not
understanding.
I gave up leaving anything to chance and started putting code like this
in the (2.0 Kernel) schedule() function:
if( first_time ) {
static unsigned long testvar = 0;
unsigned long db7;
first_time = 0;
/* maybe flush and disable the cache here. doesn't matter. */
asm ("movl %0, %%db0\n"
" movl %1, %%db7\n"
: /* no output */
:"a"(&testvar), /* put &testvar in db0 */
"b"(0x000f2202) /* watch 4 bytes for reads or writes
* at &testvar globally and set GD */
);
testvar = 0xffffffff; /* change all the bits */
/* should get a debug exception here */
printk(KERN_DEBUG "%s: any luck?\n", __FUNCTION__);
asm ("movl %%db7, %0\n" /* this movl triggers a debug exception. */
:"=a"(db7)
);
}
What am I not getting? I think there must be another bit I need to set
or the data I'm using is not properly aligned (in some way I don't
understand) or maybe this register has to be enabled by the bios? who
knows.
- Ben
On Wed, Sep 03, 2003 at 06:55:50PM -0400, Andrew Cagney wrote:
>
> Just a thought, you're not fighting a user space process playing with
> those registers?
>
> The other is to look at GDB using hardware debug registers on a user
> process.
>
> Andrew
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: how are debug registers supposed to work?
2003-08-29 0:41 how are debug registers supposed to work? Ben Johnson
2003-09-03 22:55 ` Andrew Cagney
@ 2003-09-17 0:30 ` Ben Johnson
1 sibling, 0 replies; 4+ messages in thread
From: Ben Johnson @ 2003-09-17 0:30 UTC (permalink / raw)
To: gdb
I found the problem. The addresses I'm attempting to use are logical
addresses, not linear. The (2.0) kernel data segment's base address is
0xc0000000, so in order to get a linear address I have to add that base
address to it.
altered code that's now trapping in the right place:
schedule()
{
...
static unsigned long has_run = 1;
static unsigned long has_run_2 = 0;
if( ! has_run && jiffies > 7000 )
{
has_run = 1;
has_run_2 = 0;
/* setup the debug registers */
asm ("movl %%cr4, %%edx\n" /* debug extensions */
" orl $0x8, %%edx\n"
" movl %%edx, %%cr4\n"
" movl %0, %%db0\n" /* push into db regs */
" movl %1, %%db7\n"
" lgdt 0x00106852\n" /* pentium may need this */
: /* no output */
:"a"(0xc0000000 + ((unsigned long)&has_run_2)),
"b"(0x000f2202)
/*"m"((((char *)&gdt)-6))*/
:"%edx"
);
}
if( has_run && ! has_run_2 ) /* debug reg generate exception */
{
/* whatever */
has_run_2 = 0xffffffff
}
...
}
I'm sure the debug extensions aren't needed. I put in the lgdt
instruction because I read section in 18.17.4 of Intel's Software
Development Manual (Volume 3) that it may help Pentium processors
recognize breakpoints. no other processors need that though.
- Ben
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2003-09-17 0:30 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-29 0:41 how are debug registers supposed to work? Ben Johnson
2003-09-03 22:55 ` Andrew Cagney
2003-09-04 0:17 ` Ben Johnson
2003-09-17 0:30 ` Ben Johnson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox