Commit 51c9ba11 authored by Jordan Niethe's avatar Jordan Niethe Committed by Michael Ellerman

powerpc/xmon: Move breakpoint instructions to own array

To execute an instruction out of line after a breakpoint, the NIP is set
to the address of struct bpt::instr. Here a copy of the instruction that
was replaced with a breakpoint is kept, along with a trap so normal flow
can be resumed after XOLing. The struct bpt's are located within the
data section. This is problematic as the data section may be marked as
no execute.

Instead of each struct bpt holding the instructions to be XOL'd, make a
new array, bpt_table[], with enough space to hold instructions for the
number of supported breakpoints. A later patch will move this to the
text section.
Make struct bpt::instr a pointer to the instructions in bpt_table[]
associated with that breakpoint. This association is a simple mapping:
bpts[n] -> bpt_table[n * words per breakpoint]. Currently we only need
the copied instruction followed by a trap, so 2 words per breakpoint.
Signed-off-by: default avatarJordan Niethe <jniethe5@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Reviewed-by: default avatarAlistair Popple <alistair@popple.id.au>
Link: https://lore.kernel.org/r/20200506034050.24806-3-jniethe5@gmail.com
parent 802268fd
...@@ -98,7 +98,7 @@ static long *xmon_fault_jmp[NR_CPUS]; ...@@ -98,7 +98,7 @@ static long *xmon_fault_jmp[NR_CPUS];
/* Breakpoint stuff */ /* Breakpoint stuff */
struct bpt { struct bpt {
unsigned long address; unsigned long address;
unsigned int instr[2]; unsigned int *instr;
atomic_t ref_count; atomic_t ref_count;
int enabled; int enabled;
unsigned long pad; unsigned long pad;
...@@ -117,6 +117,10 @@ static unsigned bpinstr = 0x7fe00008; /* trap */ ...@@ -117,6 +117,10 @@ static unsigned bpinstr = 0x7fe00008; /* trap */
#define BP_NUM(bp) ((bp) - bpts + 1) #define BP_NUM(bp) ((bp) - bpts + 1)
#define BPT_SIZE (sizeof(unsigned int) * 2)
#define BPT_WORDS (BPT_SIZE / sizeof(unsigned int))
static unsigned int bpt_table[NBPTS * BPT_WORDS];
/* Prototypes */ /* Prototypes */
static int cmds(struct pt_regs *); static int cmds(struct pt_regs *);
static int mread(unsigned long, void *, int); static int mread(unsigned long, void *, int);
...@@ -854,15 +858,13 @@ static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp) ...@@ -854,15 +858,13 @@ static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
{ {
unsigned long off; unsigned long off;
off = nip - (unsigned long) bpts; off = nip - (unsigned long)bpt_table;
if (off >= sizeof(bpts)) if (off >= sizeof(bpt_table))
return NULL; return NULL;
off %= sizeof(struct bpt); *offp = off % BPT_SIZE;
if (off != offsetof(struct bpt, instr[0]) if (*offp != 0 && *offp != 4)
&& off != offsetof(struct bpt, instr[1]))
return NULL; return NULL;
*offp = off - offsetof(struct bpt, instr[0]); return bpts + (off / BPT_SIZE);
return (struct bpt *) (nip - off);
} }
static struct bpt *new_breakpoint(unsigned long a) static struct bpt *new_breakpoint(unsigned long a)
...@@ -877,7 +879,8 @@ static struct bpt *new_breakpoint(unsigned long a) ...@@ -877,7 +879,8 @@ static struct bpt *new_breakpoint(unsigned long a)
for (bp = bpts; bp < &bpts[NBPTS]; ++bp) { for (bp = bpts; bp < &bpts[NBPTS]; ++bp) {
if (!bp->enabled && atomic_read(&bp->ref_count) == 0) { if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
bp->address = a; bp->address = a;
patch_instruction(&bp->instr[1], bpinstr); bp->instr = bpt_table + ((bp - bpts) * BPT_WORDS);
patch_instruction(bp->instr + 1, bpinstr);
return bp; return bp;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment