Commit 31aa02a3 authored by Richard Henderson's avatar Richard Henderson Committed by Richard Henderson

[ALPHA] Add debugging access (core and ptrace) to the

PAL unique value.  Support threaded core dumps.
parent e11c45a0
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
extern struct hwrpb_struct *hwrpb; extern struct hwrpb_struct *hwrpb;
extern void dump_thread(struct pt_regs *, struct user *); extern void dump_thread(struct pt_regs *, struct user *);
extern int dump_fpu(struct pt_regs *, elf_fpregset_t *);
extern spinlock_t rtc_lock; extern spinlock_t rtc_lock;
/* these are C runtime functions with special calling conventions: */ /* these are C runtime functions with special calling conventions: */
...@@ -144,7 +143,9 @@ EXPORT_SYMBOL(pci_dac_dma_to_offset); ...@@ -144,7 +143,9 @@ EXPORT_SYMBOL(pci_dac_dma_to_offset);
#endif #endif
EXPORT_SYMBOL(dump_thread); EXPORT_SYMBOL(dump_thread);
EXPORT_SYMBOL(dump_fpu); EXPORT_SYMBOL(dump_elf_thread);
EXPORT_SYMBOL(dump_elf_task);
EXPORT_SYMBOL(dump_elf_task_fp);
EXPORT_SYMBOL(hwrpb); EXPORT_SYMBOL(hwrpb);
EXPORT_SYMBOL(start_thread); EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(alpha_read_fp_reg); EXPORT_SYMBOL(alpha_read_fp_reg);
......
...@@ -313,7 +313,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, ...@@ -313,7 +313,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
} }
/* /*
* fill in the user structure for a core dump.. * Fill in the user structure for an ECOFF core dump.
*/ */
void void
dump_thread(struct pt_regs * pt, struct user * dump) dump_thread(struct pt_regs * pt, struct user * dump)
...@@ -373,12 +373,81 @@ dump_thread(struct pt_regs * pt, struct user * dump) ...@@ -373,12 +373,81 @@ dump_thread(struct pt_regs * pt, struct user * dump)
memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8); memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
} }
int /*
dump_fpu(struct pt_regs * regs, elf_fpregset_t *r) * Fill in the user structure for a ELF core dump.
*/
void
dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti)
{ {
/* switch stack follows right below pt_regs: */ /* switch stack follows right below pt_regs: */
struct switch_stack * sw = ((struct switch_stack *) regs) - 1; struct switch_stack * sw = ((struct switch_stack *) pt) - 1;
memcpy(r, sw->fp, 32 * 8);
dest[ 0] = pt->r0;
dest[ 1] = pt->r1;
dest[ 2] = pt->r2;
dest[ 3] = pt->r3;
dest[ 4] = pt->r4;
dest[ 5] = pt->r5;
dest[ 6] = pt->r6;
dest[ 7] = pt->r7;
dest[ 8] = pt->r8;
dest[ 9] = sw->r9;
dest[10] = sw->r10;
dest[11] = sw->r11;
dest[12] = sw->r12;
dest[13] = sw->r13;
dest[14] = sw->r14;
dest[15] = sw->r15;
dest[16] = pt->r16;
dest[17] = pt->r17;
dest[18] = pt->r18;
dest[19] = pt->r19;
dest[20] = pt->r20;
dest[21] = pt->r21;
dest[22] = pt->r22;
dest[23] = pt->r23;
dest[24] = pt->r24;
dest[25] = pt->r25;
dest[26] = pt->r26;
dest[27] = pt->r27;
dest[28] = pt->r28;
dest[29] = pt->gp;
dest[30] = rdusp();
dest[31] = pt->pc;
/* Once upon a time this was the PS value. Which is stupid
since that is always 8 for usermode. Usurped for the more
useful value of the thread's UNIQUE field. */
dest[32] = ti->pcb.unique;
}
int
dump_elf_task(elf_greg_t *dest, struct task_struct *task)
{
struct thread_info *ti;
struct pt_regs *pt;
ti = task->thread_info;
pt = (struct pt_regs *)((unsigned long)ti + 2*PAGE_SIZE) - 1;
dump_elf_thread(dest, pt, ti);
return 1;
}
int
dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
{
struct thread_info *ti;
struct pt_regs *pt;
struct switch_stack *sw;
ti = task->thread_info;
pt = (struct pt_regs *)((unsigned long)ti + 2*PAGE_SIZE) - 1;
sw = (struct switch_stack *)pt - 1;
memcpy(dest, sw->fp, 32 * 8);
return 1; return 1;
} }
......
...@@ -102,7 +102,9 @@ get_reg_addr(struct task_struct * task, unsigned long regno) ...@@ -102,7 +102,9 @@ get_reg_addr(struct task_struct * task, unsigned long regno)
if (regno == 30) { if (regno == 30) {
addr = &task->thread_info->pcb.usp; addr = &task->thread_info->pcb.usp;
} else if (regno == 31 || regno > 64) { } else if (regno == 65) {
addr = &task->thread_info->pcb.unique;
} else if (regno == 31 || regno > 65) {
zero = 0; zero = 0;
addr = &zero; addr = &zero;
} else { } else {
......
...@@ -52,53 +52,25 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; ...@@ -52,53 +52,25 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
#define ELF_PLAT_INIT(_r) _r->r0 = 0 #define ELF_PLAT_INIT(_r) _r->r0 = 0
/* Use the same format as the OSF/1 procfs interface. The register /* The registers are layed out in pt_regs for PAL and syscall
layout is sane. However, since dump_thread() creates the funky convenience. Re-order them for the linear elf_gregset_t. */
layout that ECOFF coredumps want, we need to undo that layout here.
Eventually, it would be nice if the ECOFF core-dump had to do the extern void dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt,
translation, then ELF_CORE_COPY_REGS() would become trivial and struct thread_info *ti);
faster. */ #define ELF_CORE_COPY_REGS(DEST, REGS) \
dump_elf_thread(DEST, REGS, current_thread_info());
#define ELF_CORE_COPY_REGS(_dest,_regs) \
{ \ /* Similar, but for a thread other than current. */
extern void dump_thread(struct pt_regs *, struct user *); \
struct user _dump; \ extern int dump_elf_task(elf_greg_t *dest, struct task_struct *task);
\ #define ELF_CORE_COPY_TASK_REGS(TASK, DEST) \
dump_thread(_regs, &_dump); \ dump_elf_task(*(DEST), TASK)
_dest[ 0] = _dump.regs[EF_V0]; \
_dest[ 1] = _dump.regs[EF_T0]; \ /* Similar, but for the FP registers. */
_dest[ 2] = _dump.regs[EF_T1]; \
_dest[ 3] = _dump.regs[EF_T2]; \ extern int dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task);
_dest[ 4] = _dump.regs[EF_T3]; \ #define ELF_CORE_COPY_FPREGS(TASK, DEST) \
_dest[ 5] = _dump.regs[EF_T4]; \ dump_elf_task_fp(*(DEST), TASK)
_dest[ 6] = _dump.regs[EF_T5]; \
_dest[ 7] = _dump.regs[EF_T6]; \
_dest[ 8] = _dump.regs[EF_T7]; \
_dest[ 9] = _dump.regs[EF_S0]; \
_dest[10] = _dump.regs[EF_S1]; \
_dest[11] = _dump.regs[EF_S2]; \
_dest[12] = _dump.regs[EF_S3]; \
_dest[13] = _dump.regs[EF_S4]; \
_dest[14] = _dump.regs[EF_S5]; \
_dest[15] = _dump.regs[EF_S6]; \
_dest[16] = _dump.regs[EF_A0]; \
_dest[17] = _dump.regs[EF_A1]; \
_dest[18] = _dump.regs[EF_A2]; \
_dest[19] = _dump.regs[EF_A3]; \
_dest[20] = _dump.regs[EF_A4]; \
_dest[21] = _dump.regs[EF_A5]; \
_dest[22] = _dump.regs[EF_T8]; \
_dest[23] = _dump.regs[EF_T9]; \
_dest[24] = _dump.regs[EF_T10]; \
_dest[25] = _dump.regs[EF_T11]; \
_dest[26] = _dump.regs[EF_RA]; \
_dest[27] = _dump.regs[EF_T12]; \
_dest[28] = _dump.regs[EF_AT]; \
_dest[29] = _dump.regs[EF_GP]; \
_dest[30] = _dump.regs[EF_SP]; \
_dest[31] = _dump.regs[EF_PC]; /* store PC here */ \
_dest[32] = _dump.regs[EF_PS]; \
}
/* This yields a mask that user programs can use to figure out what /* This yields a mask that user programs can use to figure out what
instruction set this CPU supports. This is trivial on Alpha, instruction set this CPU supports. This is trivial on Alpha,
......
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