iPXE
Macros | 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>

Go to the source code of this file.

Macros

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

Functions

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

Variables

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

Detailed Description

GDB architecture-specific bits for x86.

Definition in file gdbmach.c.

Macro Definition Documentation

◆ NUM_HWBP

#define NUM_HWBP   4

Number of hardware breakpoints.

Definition at line 42 of file gdbmach.c.

◆ DR7_G

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

Debug register 7: Global breakpoint enable.

Definition at line 45 of file gdbmach.c.

◆ DR7_GE

#define DR7_GE   ( 1 << 9 )

Debug register 7: Global exact breakpoint enable.

Definition at line 48 of file gdbmach.c.

◆ DR7_RWLEN_WRITE

#define DR7_RWLEN_WRITE   0x11110000

Debug register 7: Break on data writes.

Definition at line 51 of file gdbmach.c.

◆ DR7_RWLEN_ACCESS

#define DR7_RWLEN_ACCESS   0x33330000

Debug register 7: Break on data access.

Definition at line 54 of file gdbmach.c.

◆ DR7_RWLEN_1

#define DR7_RWLEN_1   0x00000000

Debug register 7: One-byte length.

Definition at line 57 of file gdbmach.c.

◆ DR7_RWLEN_2

#define DR7_RWLEN_2   0x44440000

Debug register 7: Two-byte length.

Definition at line 60 of file gdbmach.c.

◆ DR7_RWLEN_4

#define DR7_RWLEN_4   0xcccc0000

Debug register 7: Four-byte length.

Definition at line 63 of file gdbmach.c.

◆ DR7_RWLEN_8

#define DR7_RWLEN_8   0x88880000

Debug register 7: Eight-byte length.

Definition at line 66 of file gdbmach.c.

◆ DR7_RWLEN_MASK

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

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

Definition at line 69 of file gdbmach.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ gdbmach_update()

static void gdbmach_update ( void  )
static

Update debug registers.

Definition at line 81 of file gdbmach.c.

81  {
82 
83  /* Set debug registers */
84  __asm__ __volatile__ ( "mov %0, %%dr0" : : "r" ( dr[0] ) );
85  __asm__ __volatile__ ( "mov %0, %%dr1" : : "r" ( dr[1] ) );
86  __asm__ __volatile__ ( "mov %0, %%dr2" : : "r" ( dr[2] ) );
87  __asm__ __volatile__ ( "mov %0, %%dr3" : : "r" ( dr[3] ) );
88  __asm__ __volatile__ ( "mov %0, %%dr7" : : "r" ( dr7 ) );
89 }
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
static unsigned long dr[NUM_HWBP]
Hardware breakpoint addresses (debug registers 0-3)
Definition: gdbmach.c:72
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
static unsigned long dr7
Active value of debug register 7.
Definition: gdbmach.c:75

References __asm__(), __volatile__(), dr, and dr7.

Referenced by gdbmach_set_breakpoint().

◆ gdbmach_find()

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 98 of file gdbmach.c.

98  {
99  unsigned int i;
100  int bp = -ENOENT;
101 
102  /* Look for a reusable or available breakpoint */
103  for ( i = 0 ; i < NUM_HWBP ; i++ ) {
104 
105  /* If breakpoint is not enabled, then it is available */
106  if ( ! ( dr7 & DR7_G ( i ) ) ) {
107  bp = i;
108  continue;
109  }
110 
111  /* If breakpoint is enabled and has the same address
112  * and control bits, then reuse it.
113  */
114  if ( ( dr[i] == addr ) &&
115  ( ( ( dr7 ^ rwlen ) & DR7_RWLEN_MASK ( i ) ) == 0 ) ) {
116  bp = i;
117  break;
118  }
119  }
120 
121  return bp;
122 }
#define DR7_RWLEN_MASK(bp)
Debug register 7: Breakpoint R/W and length mask.
Definition: gdbmach.c:69
#define ENOENT
No such file or directory.
Definition: errno.h:514
uint16_t bp
Definition: registers.h:23
#define NUM_HWBP
Number of hardware breakpoints.
Definition: gdbmach.c:42
static unsigned long dr[NUM_HWBP]
Hardware breakpoint addresses (debug registers 0-3)
Definition: gdbmach.c:72
#define DR7_G(bp)
Debug register 7: Global breakpoint enable.
Definition: gdbmach.c:45
u32 addr
Definition: sky2.h:8
static unsigned long dr7
Active value of debug register 7.
Definition: gdbmach.c:75

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

Referenced by gdbmach_set_breakpoint().

◆ gdbmach_set_breakpoint()

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 133 of file gdbmach.c.

134  {
135  unsigned int rwlen;
136  unsigned long mask;
137  int bp;
138 
139  /* Parse breakpoint type */
140  switch ( type ) {
141  case GDBMACH_WATCH:
142  rwlen = DR7_RWLEN_WRITE;
143  break;
144  case GDBMACH_AWATCH:
145  rwlen = DR7_RWLEN_ACCESS;
146  break;
147  default:
148  return -ENOTSUP;
149  }
150 
151  /* Parse breakpoint length */
152  switch ( len ) {
153  case 1:
154  rwlen |= DR7_RWLEN_1;
155  break;
156  case 2:
157  rwlen |= DR7_RWLEN_2;
158  break;
159  case 4:
160  rwlen |= DR7_RWLEN_4;
161  break;
162  case 8:
163  rwlen |= DR7_RWLEN_8;
164  break;
165  default:
166  return -ENOTSUP;
167  }
168 
169  /* Convert to linear address */
170  if ( sizeof ( physaddr_t ) <= sizeof ( uint32_t ) )
171  addr = virt_to_phys ( ( void * ) addr );
172 
173  /* Find reusable or available hardware breakpoint */
174  bp = gdbmach_find ( addr, rwlen );
175  if ( bp < 0 )
176  return ( enable ? -ENOBUFS : 0 );
177 
178  /* Configure this breakpoint */
179  DBGC ( &dr[0], "GDB bp %d at %p+%zx type %d (%sabled)\n",
180  bp, ( ( void * ) addr ), len, type, ( enable ? "en" : "dis" ) );
181  dr[bp] = addr;
182  mask = DR7_RWLEN_MASK ( bp );
183  dr7 = ( ( dr7 & ~mask ) | ( rwlen & mask ) );
184  mask = DR7_G ( bp );
185  dr7 &= ~mask;
186  if ( enable )
187  dr7 |= mask;
188 
189  /* Update debug registers */
190  gdbmach_update();
191 
192  return 0;
193 }
#define DR7_RWLEN_MASK(bp)
Debug register 7: Breakpoint R/W and length mask.
Definition: gdbmach.c:69
uint32_t type
Operating system type.
Definition: ena.h:12
#define DBGC(...)
Definition: compiler.h:505
uint16_t bp
Definition: registers.h:23
static __always_inline unsigned long virt_to_phys(volatile const void *addr)
Convert virtual address to a physical address.
Definition: uaccess.h:361
#define DR7_RWLEN_1
Debug register 7: One-byte length.
Definition: gdbmach.c:57
#define ENOTSUP
Operation not supported.
Definition: errno.h:589
static int gdbmach_find(unsigned long addr, unsigned int rwlen)
Find reusable or available hardware breakpoint.
Definition: gdbmach.c:98
#define DR7_RWLEN_ACCESS
Debug register 7: Break on data access.
Definition: gdbmach.c:54
static unsigned long dr[NUM_HWBP]
Hardware breakpoint addresses (debug registers 0-3)
Definition: gdbmach.c:72
unsigned int uint32_t
Definition: stdint.h:12
unsigned long physaddr_t
Definition: stdint.h:20
#define DR7_RWLEN_2
Debug register 7: Two-byte length.
Definition: gdbmach.c:60
#define DR7_G(bp)
Debug register 7: Global breakpoint enable.
Definition: gdbmach.c:45
static void gdbmach_update(void)
Update debug registers.
Definition: gdbmach.c:81
#define ENOBUFS
No buffer space available.
Definition: errno.h:498
u32 addr
Definition: sky2.h:8
static unsigned long dr7
Active value of debug register 7.
Definition: gdbmach.c:75
#define DR7_RWLEN_8
Debug register 7: Eight-byte length.
Definition: gdbmach.c:66
uint32_t len
Length.
Definition: ena.h:14
#define DR7_RWLEN_WRITE
Debug register 7: Break on data writes.
Definition: gdbmach.c:51
#define DR7_RWLEN_4
Debug register 7: Four-byte length.
Definition: gdbmach.c:63

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, len, type, and virt_to_phys().

Referenced by gdbstub_breakpoint().

◆ gdbmach_handler()

__asmcall void gdbmach_handler ( int  signo,
gdbreg_t regs 
)

Handle exception.

Parameters
signoGDB signal number
regsRegister dump

Definition at line 201 of file gdbmach.c.

201  {
202  unsigned long dr7_disabled = DR7_GE;
203  unsigned long dr6_clear = 0;
204 
205  /* Temporarily disable breakpoints */
206  __asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7_disabled ) );
207 
208  /* Handle exception */
209  DBGC ( &dr[0], "GDB signal %d\n", signo );
210  DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
211  gdbstub_handler ( signo, regs );
212  DBGC ( &dr[0], "GDB signal %d returning\n", signo );
213  DBGC2_HDA ( &dr[0], 0, regs, ( GDBMACH_NREGS * sizeof ( *regs ) ) );
214 
215  /* Clear breakpoint status register */
216  __asm__ __volatile__ ( "mov %0, %%dr6\n" : : "r" ( dr6_clear ) );
217 
218  /* Re-enable breakpoints */
219  __asm__ __volatile__ ( "mov %0, %%dr7\n" : : "r" ( dr7 ) );
220 }
#define DBGC(...)
Definition: compiler.h:505
#define DR7_GE
Debug register 7: Global exact breakpoint enable.
Definition: gdbmach.c:48
#define DBGC2_HDA(...)
Definition: compiler.h:523
__asm__ __volatile__("call *%9" :"=a"(result), "=c"(discard_ecx), "=d"(discard_edx) :"d"(0), "a"(code), "b"(0), "c"(in_phys), "D"(0), "S"(out_phys), "m"(hypercall))
void gdbstub_handler(int signo, gdbreg_t *regs)
Interrupt handler.
Definition: gdbstub.c:371
static unsigned long dr[NUM_HWBP]
Hardware breakpoint addresses (debug registers 0-3)
Definition: gdbmach.c:72
struct i386_regs regs
Definition: registers.h:15
__asm__(".section \".rodata\", \"a\", " PROGBITS "\n\t" "\nprivate_key_data:\n\t" ".size private_key_data, ( . - private_key_data )\n\t" ".equ private_key_len, ( . - private_key_data )\n\t" ".previous\n\t")
static unsigned long dr7
Active value of debug register 7.
Definition: gdbmach.c:75

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

◆ gdbmach_init()

void gdbmach_init ( void  )

Initialise GDB.

Definition at line 241 of file gdbmach.c.

241  {
242  unsigned int i;
243 
244  /* Hook CPU exception vectors */
245  for ( i = 0 ; i < ( sizeof ( gdbmach_vectors ) /
246  sizeof ( gdbmach_vectors[0] ) ) ; i++ ) {
247  if ( gdbmach_vectors[i] )
249  }
250 }
static void * gdbmach_vectors[]
CPU exception vectors.
Definition: gdbmach.c:228
void set_interrupt_vector(unsigned int intr, void *vector)
Set interrupt vector.
Definition: librm_mgmt.c:97

References gdbmach_vectors, and set_interrupt_vector().

Referenced by gdbstub_start().

Variable Documentation

◆ dr

unsigned long dr[NUM_HWBP]
static

Hardware breakpoint addresses (debug registers 0-3)

Definition at line 72 of file gdbmach.c.

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

◆ dr7

unsigned long dr7 = DR7_GE
static

Active value of debug register 7.

Definition at line 75 of file gdbmach.c.

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

◆ gdbmach_vectors

void* gdbmach_vectors[]
static
Initial value:
= {
NULL,
}
void gdbmach_sigstkflt(void)
void gdbmach_sigfpe(void)
void gdbmach_sigtrap(void)
void gdbmach_sigill(void)
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321

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 228 of file gdbmach.c.

Referenced by gdbmach_init().