iPXE
Defines | Functions | Variables
gdbmach.c File Reference

GDB architecture-specific bits for x86. More...

#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
#include <ipxe/uaccess.h>
#include <ipxe/gdbstub.h>
#include <librm.h>
#include <gdbmach.h>

Go to the source code of this file.

Defines

#define NUM_HWBP   4
 Number of hardware breakpoints.
#define DR7_G(bp)   ( 2 << ( 2 * (bp) ) )
 Debug register 7: Global breakpoint enable.
#define DR7_GE   ( 1 << 9 )
 Debug register 7: Global exact breakpoint enable.
#define DR7_RWLEN_WRITE   0x11110000
 Debug register 7: Break on data writes.
#define DR7_RWLEN_ACCESS   0x33330000
 Debug register 7: Break on data access.
#define DR7_RWLEN_1   0x00000000
 Debug register 7: One-byte length.
#define DR7_RWLEN_2   0x44440000
 Debug register 7: Two-byte length.
#define DR7_RWLEN_4   0xcccc0000
 Debug register 7: Four-byte length.
#define DR7_RWLEN_8   0x88880000
 Debug register 7: Eight-byte length.
#define DR7_RWLEN_MASK(bp)   ( 0xf0000 << ( 4 * (bp) ) )
 Debug register 7: Breakpoint R/W and length mask.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static void gdbmach_update (void)
 Update debug registers.
static int gdbmach_find (unsigned long addr, unsigned int rwlen)
 Find reusable or available hardware breakpoint.
int gdbmach_set_breakpoint (int type, unsigned long addr, size_t len, int enable)
 Set hardware breakpoint.
__asmcall void gdbmach_handler (int signo, gdbreg_t *regs)
 Handle exception.
void gdbmach_init (void)
 Initialise GDB.

Variables

static unsigned long dr [NUM_HWBP]
 Hardware breakpoint addresses (debug registers 0-3)
static unsigned long dr7 = DR7_GE
 Active value of debug register 7.
static void * gdbmach_vectors []
 CPU exception vectors.

Detailed Description

GDB architecture-specific bits for x86.

Definition in file gdbmach.c.


Define Documentation

#define NUM_HWBP   4

Number of hardware breakpoints.

Definition at line 43 of file gdbmach.c.

Referenced by gdbmach_find().

#define DR7_G (   bp)    ( 2 << ( 2 * (bp) ) )

Debug register 7: Global breakpoint enable.

Definition at line 46 of file gdbmach.c.

Referenced by gdbmach_find(), and gdbmach_set_breakpoint().

#define DR7_GE   ( 1 << 9 )

Debug register 7: Global exact breakpoint enable.

Definition at line 49 of file gdbmach.c.

Referenced by gdbmach_handler().

#define DR7_RWLEN_WRITE   0x11110000

Debug register 7: Break on data writes.

Definition at line 52 of file gdbmach.c.

Referenced by gdbmach_set_breakpoint().

#define DR7_RWLEN_ACCESS   0x33330000

Debug register 7: Break on data access.

Definition at line 55 of file gdbmach.c.

Referenced by gdbmach_set_breakpoint().

#define DR7_RWLEN_1   0x00000000

Debug register 7: One-byte length.

Definition at line 58 of file gdbmach.c.

Referenced by gdbmach_set_breakpoint().

#define DR7_RWLEN_2   0x44440000

Debug register 7: Two-byte length.

Definition at line 61 of file gdbmach.c.

Referenced by gdbmach_set_breakpoint().

#define DR7_RWLEN_4   0xcccc0000

Debug register 7: Four-byte length.

Definition at line 64 of file gdbmach.c.

Referenced by gdbmach_set_breakpoint().

#define DR7_RWLEN_8   0x88880000

Debug register 7: Eight-byte length.

Definition at line 67 of file gdbmach.c.

Referenced by gdbmach_set_breakpoint().

#define DR7_RWLEN_MASK (   bp)    ( 0xf0000 << ( 4 * (bp) ) )

Debug register 7: Breakpoint R/W and length mask.

Definition at line 70 of file gdbmach.c.

Referenced by gdbmach_find(), and gdbmach_set_breakpoint().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static void gdbmach_update ( void  ) [static]

Update debug registers.

Definition at line 82 of file gdbmach.c.

References __asm__(), dr, and dr7.

Referenced by gdbmach_set_breakpoint().

                                    {

        /* Set debug registers */
        __asm__ __volatile__ ( "mov %0, %%dr0" : : "r" ( dr[0] ) );
        __asm__ __volatile__ ( "mov %0, %%dr1" : : "r" ( dr[1] ) );
        __asm__ __volatile__ ( "mov %0, %%dr2" : : "r" ( dr[2] ) );
        __asm__ __volatile__ ( "mov %0, %%dr3" : : "r" ( dr[3] ) );
        __asm__ __volatile__ ( "mov %0, %%dr7" : : "r" ( dr7 ) );
}
static int gdbmach_find ( unsigned long  addr,
unsigned int  rwlen 
) [static]

Find reusable or available hardware breakpoint.

Parameters:
addrLinear address
rwlenControl bits
Return values:
bpHardware breakpoint, or negative error

Definition at line 99 of file gdbmach.c.

References bp, dr, dr7, DR7_G, DR7_RWLEN_MASK, ENOENT, and NUM_HWBP.

Referenced by gdbmach_set_breakpoint().

                                                                   {
        unsigned int i;
        int bp = -ENOENT;

        /* Look for a reusable or available breakpoint */
        for ( i = 0 ; i < NUM_HWBP ; i++ ) {

                /* If breakpoint is not enabled, then it is available */
                if ( ! ( dr7 & DR7_G ( i ) ) ) {
                        bp = i;
                        continue;
                }

                /* If breakpoint is enabled and has the same address
                 * and control bits, then reuse it.
                 */
                if ( ( dr[i] == addr ) &&
                     ( ( ( dr7 ^ rwlen ) & DR7_RWLEN_MASK ( i ) ) == 0 ) ) {
                        bp = i;
                        break;
                }
        }

        return bp;
}
int gdbmach_set_breakpoint ( int  type,
unsigned long  addr,
size_t  len,
int  enable 
)

Set hardware breakpoint.

Parameters:
typeGDB breakpoint type
addrVirtual address
lenLength
enableEnable (not disable) breakpoint
Return values:
rcReturn status code

Definition at line 134 of file gdbmach.c.

References addr, bp, DBGC, dr, dr7, DR7_G, DR7_RWLEN_1, DR7_RWLEN_2, DR7_RWLEN_4, DR7_RWLEN_8, DR7_RWLEN_ACCESS, DR7_RWLEN_MASK, DR7_RWLEN_WRITE, ENOBUFS, ENOTSUP, GDBMACH_AWATCH, gdbmach_find(), gdbmach_update(), GDBMACH_WATCH, and virt_to_phys().

Referenced by gdbstub_breakpoint().

                                          {
        unsigned int rwlen;
        unsigned long mask;
        int bp;

        /* Parse breakpoint type */
        switch ( type ) {
        case GDBMACH_WATCH:
                rwlen = DR7_RWLEN_WRITE;
                break;
        case GDBMACH_AWATCH:
                rwlen = DR7_RWLEN_ACCESS;
                break;
        default:
                return -ENOTSUP;
        }

        /* Parse breakpoint length */
        switch ( len ) {
        case 1:
                rwlen |= DR7_RWLEN_1;
                break;
        case 2:
                rwlen |= DR7_RWLEN_2;
                break;
        case 4:
                rwlen |= DR7_RWLEN_4;
                break;
        case 8:
                rwlen |= DR7_RWLEN_8;
                break;
        default:
                return -ENOTSUP;
        }

        /* Convert to linear address */
        if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
                addr = virt_to_phys ( ( void * ) addr );

        /* Find reusable or available hardware breakpoint */
        bp = gdbmach_find ( addr, rwlen );
        if ( bp < 0 )
                return ( enable ? -ENOBUFS : 0 );

        /* Configure this breakpoint */
        DBGC ( &dr[0], "GDB bp %d at %p+%zx type %d (%sabled)\n",
               bp, ( ( void * ) addr ), len, type, ( enable ? "en" : "dis" ) );
        dr[bp] = addr;
        mask = DR7_RWLEN_MASK ( bp );
        dr7 = ( ( dr7 & ~mask ) | ( rwlen & mask ) );
        mask = DR7_G ( bp );
        dr7 &= ~mask;
        if ( enable )
                dr7 |= mask;

        /* Update debug registers */
        gdbmach_update();

        return 0;
}
__asmcall void gdbmach_handler ( int  signo,
gdbreg_t regs 
)

Handle exception.

Parameters:
signoGDB signal number
regsRegister dump

Definition at line 202 of file gdbmach.c.

References __asm__(), DBGC, DBGC2_HDA, dr, dr7, DR7_GE, GDBMACH_NREGS, and gdbstub_handler().

                                                             {
        unsigned long dr7_disabled = DR7_GE;
        unsigned long dr6_clear = 0;

        /* Temporarily disable breakpoints */
        __asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7_disabled ) );

        /* Handle exception */
        DBGC ( &dr[0], "GDB signal %d\n", signo );
        DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
        gdbstub_handler ( signo, regs );
        DBGC ( &dr[0], "GDB signal %d returning\n", signo );
        DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );

        /* Clear breakpoint status register */
        __asm__ __volatile__ ( "mov %0, %%dr6\n" : : "r" ( dr6_clear ) );

        /* Re-enable breakpoints */
        __asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7 ) );
}
void gdbmach_init ( void  )

Initialise GDB.

Definition at line 242 of file gdbmach.c.

References gdbmach_vectors, and set_interrupt_vector().

Referenced by gdbstub_start().

                           {
        unsigned int i;

        /* Hook CPU exception vectors */
        for ( i = 0 ; i < ( sizeof ( gdbmach_vectors ) /
                            sizeof ( gdbmach_vectors[0] ) ) ; i++ ) {
                if ( gdbmach_vectors[i] )
                        set_interrupt_vector ( i, gdbmach_vectors[i] );
        }
}

Variable Documentation

unsigned long dr[NUM_HWBP] [static]

Hardware breakpoint addresses (debug registers 0-3)

Definition at line 73 of file gdbmach.c.

Referenced by gdbmach_find(), gdbmach_handler(), gdbmach_set_breakpoint(), and gdbmach_update().

unsigned long dr7 = DR7_GE [static]

Active value of debug register 7.

Definition at line 76 of file gdbmach.c.

Referenced by gdbmach_find(), gdbmach_handler(), gdbmach_set_breakpoint(), and gdbmach_update().

void* gdbmach_vectors[] [static]
Initial value:

CPU exception vectors.

Note that we cannot intercept anything from INT8 (double fault) upwards, since these overlap by default with IRQ0-7.

Definition at line 229 of file gdbmach.c.

Referenced by gdbmach_init().