[Patch 2/2] MIPS hardware watchpoint support.

David Daney ddaney@caviumnetworks.com
Thu Apr 16 17:08:00 GMT 2009


Pedro Alves wrote:
> On Monday 06 April 2009 08:27:07, David Daney wrote:
>> Support for hardware watchpoints for mips-linux was merged into the 
>> Linux kernel for version 2.6.28, with some bug fixes in 2.6.29.  This 
>> patch adds the corresponding gdb support.  It has been tested on both 
>> mipsel-linux (32-bit kernel) and mips64-linux (64-bit kernel).
> 
> Thanks!  I'll pretend to know a thing about mips from here on, and
> hope that it doesn't show too much that I don't.
> 
> In general, this looks very good to me, although I didn't
> make an effort to understand all the bit juggling going on.  Minor
> comments to the code below.  Then comments to the tests follow that.
> 
>> 2009-04-05  David Daney  <ddaney@caviumnetworks.com>
> 
>>         (get_irw_mask, get_reg_mask, get_num_valid, get_watchlo,
>>         set_watchlo, get_watchhi, set_watchhi, mips_show_dr,
> 
> Please split these context lines like so instead, as per the
> coding conventions:
> 
>>         (get_irw_mask, get_reg_mask, get_num_valid, get_watchlo)
>>         (set_watchlo, get_watchhi, set_watchhi, mips_show_dr)
> 
> 

Done.  All these years and there is still more to learn about the coding 
conventions.

>> +/* Assuming usable watch registers, return the irw_mask.  */
>> +static uint32_t
> 
> Please add an empty line between comment and function.  Here
> and elsewhere.

Done.

> 
>> +get_irw_mask (struct pt_watch_regs *regs, int set)
>> +{
>> +  switch (regs->style)
>> +    {
>> +    case pt_watch_style_mips32:
>> +      return regs->mips32.watch_masks[set] & IRW_MASK;
>> +    case pt_watch_style_mips64:
>> +      return regs->mips64.watch_masks[set] & IRW_MASK;
>> +    default:
>> +      gdb_assert (0);
> 
> Please don't write 'gdb_assert (0)', instead make that a
> more bit more friendly `internal_error'.  Here and
> elsewhere.
> 

Done.

>> +    printf_unfiltered (" (addr=%lx, len=%d, type=%s)",
>> +                      /* This code is for mips, so casting CORE_ADDR
>> +                         to unsigned long should be okay.  */
>> +                      (unsigned long)addr, len,
> 
> Why bother to explain that instead of using `paddr'?  If there's
> a reason, then it would be nice if it was spelled out in the
> comment.

Comment deleted, and types casted to (unsigned long long).


>> +  for (i = 0; i < MAX_DEBUG_REGISTER; i++)
>> +    {
> 
> Unneeded braces.  You have a couple more in the patch.

Fixed.

> 
>> +      printf_unfiltered ("\tDR%d: lo=0x%s, hi=0x%s\n",
>> +                        i, paddr (get_watchlo (&watch_mirror, i)),
>> +                        paddr (get_watchhi (&watch_mirror, i)));
>> +    }
>> +}
>> +

>> +       {
>> +         perror_with_name (_("Couldn't write debug register"));
>> +         return -1;
> 
> perror doesn't return, no need for `return -1'.

Fixed.


>> +
>> +  watch_mirror = watch_readback;
>> +  populate_regs_from_watches (&watch_mirror);
>> +
>> +  retval = write_watchpoint_regs();
> 
>                                    ^ missing space.


All instances fixed.


>> +  deprecated_add_set_cmd ("show-debug-regs", class_maintenance,
>> +                         var_boolean, (char *) &maint_show_dr, _("\
>> +Set whether to show variables that mirror the mips debug registers.\n\
>> +Use \"on\" to enable, \"off\" to disable.\n\
>> +If enabled, the debug registers values are shown when GDB inserts\n\
>> +or removes a hardware breakpoint or watchpoint, and when the inferior\n\
>> +triggers a breakpoint or watchpoint."),
>> +                         &maintenancelist);
> 
> Argh.  I've posted a patch that removes deprecated_add_set_cmd, but
> never got around to committing it.
> 
>  http://sourceware.org/ml/gdb-patches/2009-01/msg00119.html
> 
> When I get around to finish off that patch, I'll adjust this
> file too --- I assume that is OK with you.
> 
> However, reusing the x86 command does avoid needing to document
> it, but, could you remove the reference to x86 in the current
> docs?
> 
>  @kindex maint show-debug-regs
>  @cindex x86 hardware debug registers
>  @item maint show-debug-regs
>  Control whether to show variables that mirror the x86 hardware debug
>  registers.  Use @code{ON} to enable, @code{OFF} to disable.  If
>  enabled, the debug registers values are shown when @value{GDBN} inserts or
>  removes a hardware breakpoint or watchpoint, and when the inferior
>  triggers a hardware-assisted breakpoint or watchpoint.
> 
> ... since it now applies to mips as well.

Done.


>> For this submission I tested on a mipsel-linux system with these results 
>> (with comments):
>>
>> --- ./gdb/testsuite/gdb.sum    2009-04-05 20:53:20.000000000 -0700
>> +++ gdb.sum    2009-04-05 17:53:05.000000000 -0700
>> @@ -1,4 +1,4 @@
>> -Test Run By root on Sun Apr  5 18:08:05 2009
>> +Test Run By root on Sun Apr  5 14:45:02 2009
>>  Native configuration is mipsel-unknown-linux-gnu
>>  
>>          === gdb tests ===
>> @@ -5717,15 +5717,15 @@
>>  PASS: gdb.base/recurse.exp: continue to recurse (a = 5)
>>  PASS: gdb.base/recurse.exp: next over b = 0 in second instance
>>  PASS: gdb.base/recurse.exp: set second instance watchpoint
>> -PASS: gdb.base/recurse.exp: continue to second instance watchpoint, 
>> first time
>> -PASS: gdb.base/recurse.exp: continue to recurse (a = 4)
>> -PASS: gdb.base/recurse.exp: continue to recurse (a = 3)
>> -PASS: gdb.base/recurse.exp: continue to recurse (a = 2)
>> -PASS: gdb.base/recurse.exp: continue to recurse (a = 1)
>> -PASS: gdb.base/recurse.exp: continue to second instance watchpoint, 
>> second time
>> -PASS: gdb.base/recurse.exp: second instance watchpoint deleted when 
>> leaving scope
>> -PASS: gdb.base/recurse.exp: continue to first instance watchpoint, 
>> second time
>> -PASS: gdb.base/recurse.exp: first instance watchpoint deleted when 
>> leaving scope
>> +FAIL: gdb.base/recurse.exp: continue to second instance watchpoint, 
>> first time
>> +FAIL: gdb.base/recurse.exp: continue to recurse (a = 4)
>> +FAIL: gdb.base/recurse.exp: continue to recurse (a = 3)
>> +FAIL: gdb.base/recurse.exp: continue to recurse (a = 2)
>> +FAIL: gdb.base/recurse.exp: continue to recurse (a = 1)
>> +FAIL: gdb.base/recurse.exp: continue to second instance watchpoint, 
>> second time
>> +FAIL: gdb.base/recurse.exp: second instance watchpoint deleted when 
>> leaving scope
>> +FAIL: gdb.base/recurse.exp: continue to first instance watchpoint, 
>> second time
>> +FAIL: gdb.base/recurse.exp: first instance watchpoint deleted when 
>> leaving scope
>>
>> These failures are caused by the fact that the test assumes more than a 
>> the single watch register supported by the test system.  Although this 
>> patch supports up to eight registers, the test platform only has one.  
>> We return true from mips_linux_can_use_hw_breakpoint for multiple 
>> requests as it is not possible to know how many watchpoints are 
>> enabled.  Later gdb tries to insert more than one watchpoint and all but 
>> the first fail.
> 
> Could we detect that, and fail the rest of the test gracefully?
> What error message do you get?
> 

I slightly modified the patch so that it makes more conservative 
estimates about how many hardware watches it can handle.  This fixes 
these failures.


> 
>> -PASS: gdb.mi/mi-watch.exp: hw: watchpoint trigger
>> +FAIL: gdb.mi/mi-watch.exp: hw: watchpoint trigger (unknown output after 
>> running)
>>
>> Reported instruction location of the watchpoint trigger is one 
>> instruction later and one line later.
> 
> Why is that?

I was mistaken, it is earlier, not later.  With hardware watch points, 
$pc points to the faulting instruction, with software watch points $pc 
points to the following instruction.  In a couple of tests, this results 
in the reported line number being different than the expected value.



Here is the revised patch and its test results:

--- pre/gdb.sum	2009-04-15 12:12:33.000000000 -0700
+++ post/gdb.sum	2009-04-15 10:22:37.000000000 -0700
@@ -1,4 +1,4 @@
-Test Run By root on Wed Apr 15 10:42:35 2009
+Test Run By root on Tue Apr 14 16:28:52 2009
  Native configuration is mips64-unknown-linux-gnu

  		=== gdb tests ===
@@ -5684,7 +5684,7 @@
  PASS: gdb.base/recurse.exp: continue to recurse (a = 1)
  PASS: gdb.base/recurse.exp: continue to second instance watchpoint, 
second time
  PASS: gdb.base/recurse.exp: second instance watchpoint deleted when 
leaving scope
-PASS: gdb.base/recurse.exp: continue to first instance watchpoint, 
second time
+FAIL: gdb.base/recurse.exp: continue to first instance watchpoint, 
second time

Different line number as explained above.


  PASS: gdb.base/recurse.exp: first instance watchpoint deleted when 
leaving scope
  Running ../../../src/gdb/testsuite/gdb.base/regs.exp ...
  Running ../../../src/gdb/testsuite/gdb.base/relational.exp ...
@@ -8272,26 +8272,26 @@
  PASS: gdb.base/watch_thread_num.exp: Disable breakpoint 2
  PASS: gdb.base/watch_thread_num.exp: Watchpoint on shared variable
  PASS: gdb.base/watch_thread_num.exp: info breakpoint 3
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 1 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 1 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 2 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 2 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 3 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 3 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 4 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 4 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 5 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 5 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 6 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 6 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 7 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 7 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 8 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 8 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 9 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 9 (timeout)
-FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 10 
(timeout)
-FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 10 (timeout)
+PASS: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 1
+PASS: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 1
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 2
+FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 2
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 3
+PASS: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 3
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 4
+FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 4
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 5
+FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 5
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 6
+FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 6
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 7
+FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 7
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 8
+PASS: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 8
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 9
+FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 9
+FAIL: gdb.base/watch_thread_num.exp: Watchpoint triggered iteration 10
+FAIL: gdb.base/watch_thread_num.exp: Check thread that triggered 
iteration 10
  Running ../../../src/gdb/testsuite/gdb.base/watchpoint-hw.exp ...
  Running ../../../src/gdb/testsuite/gdb.base/watchpoint-solib.exp ...
  PASS: gdb.base/watchpoint-solib.exp: set pending breakpoint
@@ -8476,7 +8476,7 @@
  PASS: gdb.cp/annota2.exp: breakpoint at main
  PASS: gdb.cp/annota2.exp: run until main breakpoint
  PASS: gdb.cp/annota2.exp: set watch on a.x
-PASS: gdb.cp/annota2.exp: watch triggered on a.x
+FAIL: gdb.cp/annota2.exp: watch triggered on a.x
  PASS: gdb.cp/annota2.exp: annotate-quit
  Running ../../../src/gdb/testsuite/gdb.cp/annota3.exp ...
  PASS: gdb.cp/annota3.exp: breakpoint main
@@ -8488,7 +8488,7 @@
  PASS: gdb.cp/annota3.exp: break at main
  PASS: gdb.cp/annota3.exp: second run until main breakpoint
  PASS: gdb.cp/annota3.exp: set watch on a.x
-PASS: gdb.cp/annota3.exp: watch triggered on a.x
+FAIL: gdb.cp/annota3.exp: watch triggered on a.x

The two annotation failures are explained in the

  PASS: gdb.cp/annota3.exp: annotate-quit
  Running ../../../src/gdb/testsuite/gdb.cp/anon-union.exp ...
  PASS: gdb.cp/anon-union.exp: next 1
@@ -11976,7 +11976,7 @@
  PASS: gdb.mi/mi-watch.exp: hw: mi runto callee4
  PASS: gdb.mi/mi-watch.exp: hw: break-watch operation
  PASS: gdb.mi/mi-watch.exp: hw: list of watchpoints
-PASS: gdb.mi/mi-watch.exp: hw: watchpoint trigger
+FAIL: gdb.mi/mi-watch.exp: hw: watchpoint trigger (unknown output after 
running)

Different line number as explained above.

  PASS: gdb.mi/mi-watch.exp: hw: watchpoint trigger
  Running ../../../src/gdb/testsuite/gdb.mi/mi2-basics.exp ...
  PASS: gdb.mi/mi2-basics.exp: acceptance of MI operations
@@ -12609,7 +12609,7 @@
  PASS: gdb.mi/mi2-watch.exp: hw: mi runto callee4
  PASS: gdb.mi/mi2-watch.exp: hw: break-watch operation
  PASS: gdb.mi/mi2-watch.exp: hw: list of watchpoints
-PASS: gdb.mi/mi2-watch.exp: hw: watchpoint trigger
+FAIL: gdb.mi/mi2-watch.exp: hw: watchpoint trigger (unknown output 
after running)

Different line number as explained above.

  PASS: gdb.mi/mi2-watch.exp: hw: watchpoint trigger
  Running ../../../src/gdb/testsuite/gdb.modula2/unbounded-array.exp ...
  PASS: gdb.modula2/unbounded-array.exp: switch to modula-2
@@ -13351,10 +13351,10 @@
  PASS: gdb.threads/tls.exp: info address a_thread_local
  Running ../../../src/gdb/testsuite/gdb.threads/watchthreads.exp ...
  PASS: gdb.threads/watchthreads.exp: successfully compiled posix 
threads test case
-FAIL: gdb.threads/watchthreads.exp: watch args[0]
+PASS: gdb.threads/watchthreads.exp: watch args[0]
  FAIL: gdb.threads/watchthreads.exp: watch args[1]
  FAIL: gdb.threads/watchthreads.exp: threaded watch loop
-FAIL: gdb.threads/watchthreads.exp: first watchpoint on args[0] hit
+PASS: gdb.threads/watchthreads.exp: first watchpoint on args[0] hit
  FAIL: gdb.threads/watchthreads.exp: first watchpoint on args[1] hit
  FAIL: gdb.threads/watchthreads.exp: watchpoint on args[0] hit in thread
  FAIL: gdb.threads/watchthreads.exp: watchpoint on args[1] hit in thread



OK to commit?

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: mips-watch.patch
URL: <http://sourceware.org/pipermail/gdb-patches/attachments/20090416/36bf0461/attachment.ksh>


More information about the Gdb-patches mailing list