From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18337 invoked by alias); 29 Aug 2003 00:41:36 -0000 Mailing-List: contact gdb-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-owner@sources.redhat.com Received: (qmail 18324 invoked from network); 29 Aug 2003 00:41:33 -0000 Received: from unknown (HELO animal.blarg.net) (206.124.128.1) by sources.redhat.com with SMTP; 29 Aug 2003 00:41:33 -0000 Received: by animal.blarg.net (Postfix, from userid 3118) id B96FB6F5B0; Thu, 28 Aug 2003 17:41:29 -0700 (PDT) Date: Fri, 29 Aug 2003 00:41:00 -0000 From: Ben Johnson To: gdb@sources.redhat.com Subject: how are debug registers supposed to work? Message-ID: <20030828174129.B9184@blarg.net> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5.1i X-SW-Source: 2003-08/txt/msg00320.txt.bz2 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 ######################################################################## 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