summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Niethe <jniethe5@gmail.com>2020-05-06 13:40:22 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2020-05-19 00:10:36 +1000
commit51c9ba11f17f25ace1ea6bbfd4586c59105432de (patch)
treefc73c26d5e4a31cdff40251d7f30c5c4a1f4b6b9
parent802268fd82676ffce432776f60b93a0b15e58e0c (diff)
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: Jordan Niethe <jniethe5@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Reviewed-by: Alistair Popple <alistair@popple.id.au> Link: https://lore.kernel.org/r/20200506034050.24806-3-jniethe5@gmail.com
-rw-r--r--arch/powerpc/xmon/xmon.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index f65cb5bafc0f..afb28ad660a7 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -98,7 +98,7 @@ static long *xmon_fault_jmp[NR_CPUS];
/* Breakpoint stuff */
struct bpt {
unsigned long address;
- unsigned int instr[2];
+ unsigned int *instr;
atomic_t ref_count;
int enabled;
unsigned long pad;
@@ -117,6 +117,10 @@ static unsigned bpinstr = 0x7fe00008; /* trap */
#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 */
static int cmds(struct pt_regs *);
static int mread(unsigned long, void *, int);
@@ -854,15 +858,13 @@ static struct bpt *in_breakpoint_table(unsigned long nip, unsigned long *offp)
{
unsigned long off;
- off = nip - (unsigned long) bpts;
- if (off >= sizeof(bpts))
+ off = nip - (unsigned long)bpt_table;
+ if (off >= sizeof(bpt_table))
return NULL;
- off %= sizeof(struct bpt);
- if (off != offsetof(struct bpt, instr[0])
- && off != offsetof(struct bpt, instr[1]))
+ *offp = off % BPT_SIZE;
+ if (*offp != 0 && *offp != 4)
return NULL;
- *offp = off - offsetof(struct bpt, instr[0]);
- return (struct bpt *) (nip - off);
+ return bpts + (off / BPT_SIZE);
}
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) {
if (!bp->enabled && atomic_read(&bp->ref_count) == 0) {
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;
}
}