This is the mail archive of the gdb@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]