This is the mail archive of the gdb@sourceware.org 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]

GDB Watchpoints and the PTRACE interface for different ppc processors


Hi Paul,

I'm writting this in the hope of getting a better solution to the
current PTRACE interface problem we are facing on GDB while trying to
cope with two different processors that have different debug register
formats (PowerPC 440 and PowerPC 970).

The main question is, should GDB deal with all the bit-setting logic for
each specific processor and send the PTRACE parameters ready to be
assigned to the task's debug register? Or should the kernel receive high
level definitions of watchpoints (GDB would just request a read
watchpoint, or a write watchpoint) through PTRACE and would have all the
logic required to set the correct bits for each specific processor?

Follows below a detailed explanation of the problem.

I was originally working on supporting Hardware Watchpoints on the
PowerPC 440 processors. These processors carry a DBCR0 register that
controls the two possible modes of operation for a watchpoint:
read/write. So we have two bits that must to be set in that specific
register in order to enable the mode we want.

These bits are located in the middle of the register. If i'm not
mistaken, they are located on bits 13 and 14, in a 32-bit wide DBCR0.

So, this is how we set the watchpoint on gdb's side for the 440's:

=============GDB code=======================
long dabr_value;

  dabr_value = addr & ~3; /* Clear the 2 bits we're going to use */

  switch (rw)
    {
    case hw_read:
      /* Set read bit.  */
      dabr_value |= 1;
      break;
    case hw_write:
      /* Set write bit.  */
      dabr_value |= 2;
      break;
    case hw_access:
      /* Set read, write bits.  */
      dabr_value |= 3;
      break;
    }

ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value);

============================================

So, basically we set two bits (the last bits, 30 and 31) for read/write
modes and send that information to the kernel through PTRACE request
PTRACE_SET_DEBUGREG.

On the kernel side we have the following:

===========Kernel code============
if (data & 1)
	task->thread.dbcr0 |= DBCR_D1R;
if (data & 2)
	task->thread.dbcr0 |= DBCR_D1W;
==================================

In this code, the kernel checks the previously set bits (30 and 31) on
data (dabr_value) and move the bit values to the correct position (13
and 14) through two defined constants (DBCR_D1R and DBCR_D1W). This
magic happens inside the kernel. Additionally, there are other bits that
are set automatically by the kernel without GDB knowing that.

This covers the case for the PowerPC 440 processors.

As for the 970/970FX (JS20/21), we have a different debug register,
called DABR, that we use to set hardware watchpoints. We still have to
set the read/write bits for it, but in this case, the bits are located
in the last bits (62 and 63) in a 64-bit wide register, different than
the 440's bits positions.

Additionaly, for the 970, we also set a third flag in GDB, the
"Breakpoint Translation Enable" flag (bit 61).

So, for the 970's case, we have the following GDB code:

=============GDB code=======================
long dabr_value;

  ptid_t ptid = inferior_ptid;

  dabr_value = addr & ~7; /* Clear the 3 bits we're going to use */

  switch (rw)
    {
    case hw_read:
      /* Set read bit + translate bit.  */
      dabr_value |= 5;
      break;
    case hw_write:
      /* Set write bit + translate bit.  */
      dabr_value |= 6;
      break;
    case hw_access:
      /* Set read, write bits + translate bit.  */
      dabr_value |= 7;
      break;
    }

ptrace (PTRACE_SET_DEBUGREG, tid, 0, dabr_value);
============================================

In here we're using 3 bits to set the needed flags. The kernel code for
the 970's is the following.

===========Kernel code============
task->thread.dabr = data;
==================================

So, the kernel-side just assigns the parameter we've passed via PTRACE
on GDB to the task's debug register. There is no bit position shifting
involved in this case (as opposed to the 440's kernel code), and GDB is
also setting an additional flag (Breakpoint translation enable).

Best regards,
-- 
Luis Machado
IBM Linux Technology Center
e-mail: luisgpm@linux.vnet.ibm.com


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