Newer
Older
#include <stdio.h>
#include <machine/trap.h>
#include "lisp.h"
#include "globals.h"
#include "validate.h"
#include "os.h"
#include "arch.h"
#include "lispregs.h"
#include "signal.h"
#include "internals.h"
#include "breakpoint.h"
char *arch_init(void)
{
return NULL;
}
os_vm_address_t arch_get_bad_addr(int signal,
int code,
struct sigcontext *scp)
#ifdef hpux
struct save_state *state;
os_vm_address_t addr;
state = (struct save_state *)(&(scp->sc_sl.sl_ss));
if (state == NULL)
return NULL;
/* Check the instruction address first. */
addr = scp->sc_pcoq_head & ~3;
if (addr < 0x1000)
return addr;
/* Otherwise, it must have been a data fault. */
return state->ss_cr21;
#else
struct hp800_thread_state *state;
os_vm_address_t addr;
state = (struct hp800_thread_state *)(scp->sc_ap);
if (state == NULL)
return NULL;
/* Check the instruction address first. */
addr = scp->sc_pcoqh & ~3;
if (addr < 0x1000)
return addr;
/* Otherwise, it must have been a data fault. */
return state->cr21;
#endif
}
unsigned char *arch_internal_error_arguments(struct sigcontext *scp)
{
#ifdef hpux
return (unsigned char *)((scp->sc_pcoq_head&~0x3)+4);
#else
#endif
}
boolean arch_pseudo_atomic_atomic(struct sigcontext *scp)
{
/* Pseudo-atomic-atomic is implemented by oring 0x4 into ALLOC. */
if (SC_REG(scp, reg_ALLOC) & 0x4)
return TRUE;
else
return FALSE;
}
void arch_set_pseudo_atomic_interrupted(struct sigcontext *scp)
{
/* Pseudo-atomic-atomic is implemented by oring 0x1 into ALLOC. */
SC_REG(scp, reg_ALLOC) |= 1;
}
void arch_skip_instruction(struct sigcontext *scp)
{
/* Skip the offending instruction */
#ifdef hpux
scp->sc_pcoq_head = scp->sc_pcoq_tail;
scp->sc_pcoq_tail += 4;
#else
#endif
}
unsigned long arch_install_breakpoint(void *pc)
{
unsigned long *ulpc = (unsigned long *)pc;
unsigned long orig_inst = *ulpc;
*ulpc = trap_Breakpoint;
return orig_inst;
}
void arch_remove_breakpoint(void *pc, unsigned long orig_inst)
{
unsigned long *ulpc = (unsigned long *)pc;
*ulpc = orig_inst;
}
void arch_do_displaced_inst(struct sigcontext *scp, unsigned long orig_inst)
{
/* We set the recovery counter to cover one instruction, put the */
/* original instruction back in, and then resume. We will then trap */
/* after executing that one instruction, at which time we can put */
/* the breakpoint back in. */
#ifdef hpux
scp->sc_sl.sl_ss.ss_cr0 = 1;
scp->sc_flags |= 0x10;
#else
((struct hp800_thread_state *)scp->sc_ap)->cr0 = 1;
scp->sc_ps |= 0x10;
#endif
*(unsigned long *)SC_PC(scp) = orig_inst;
undo_fake_foreign_function_call(scp);
#ifdef hpux
printf("ERROR: arch_do_displaced_inst doesn't work because no sigreturn\n");
#else
#endif
}
static void sigtrap_handler(int signal, int code, struct sigcontext *scp)
{
unsigned long bad_inst;
sigsetmask(scp->sc_mask);
#if 0
printf("sigtrap_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
SC_REG(scp,reg_ALLOC));
#endif
#ifdef hpux
bad_inst = *(unsigned long *)(scp->sc_pcoq_head & ~3);
#else
#endif
if (bad_inst & 0xfc001fe0)
interrupt_handle_now(signal, code, scp);
else {
int im5 = bad_inst & 0x1f;
switch (im5) {
case trap_Halt:
fake_foreign_function_call(scp);
lose("%%primitive halt called; the party is over.\n");
case trap_PendingInterrupt:
arch_skip_instruction(scp);
interrupt_handle_pending(scp);
break;
case trap_Error:
case trap_Cerror:
interrupt_internal_error(signal, code, scp, im5==trap_Cerror);
break;
case trap_Breakpoint:
sigsetmask(scp->sc_mask);
fake_foreign_function_call(scp);
handle_breakpoint(signal, code, scp);
undo_fake_foreign_function_call(scp);
break;
case trap_FunctionEndBreakpoint:
sigsetmask(scp->sc_mask);
fake_foreign_function_call(scp);
{
void *pc;
pc = handle_function_end_breakpoint(signal, code, scp);
#ifdef hpux
scp->sc_pcoq_head = (unsigned long)pc;
scp->sc_pcoq_tail = (unsigned long)pc + 4;
#else
scp->sc_pcoqh = (unsigned long)pc;
scp->sc_pcoqt = (unsigned long)pc + 4;
#endif
}
undo_fake_foreign_function_call(scp);
break;
default:
interrupt_handle_now(signal, code, scp);
break;
}
}
}
static void sigfpe_handler(int signal, int code, struct sigcontext *scp)
{
unsigned long badinst;
int opcode, r1, r2, t;
long op1, op2, res;
#if 0
printf("sigfpe_handler, pc=0x%08x, alloc=0x%08x\n", scp->sc_pcoqh,
SC_REG(scp,reg_ALLOC));
#endif
switch (code) {
case I_OVFLO:
badinst = *(unsigned long *)(SC_PC(scp)&~3);
opcode = badinst >> 26;
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
if (opcode == 2) {
/* reg/reg inst. */
r1 = (badinst >> 16) & 0x1f;
op1 = fixnum_value(SC_REG(scp, r1));
r2 = (badinst >> 21) & 0x1f;
op2 = fixnum_value(SC_REG(scp, r2));
t = badinst & 0x1f;
switch ((badinst >> 5) & 0x7f) {
case 0x70:
/* Add and trap on overflow. */
res = op1 + op2;
break;
case 0x60:
/* Subtract and trap on overflow. */
res = op1 - op2;
break;
default:
goto not_interesting;
}
}
else if ((opcode & 0x37) == 0x25 && (badinst & (1<<11))) {
/* Add or subtract immediate. */
op1 = ((badinst >> 3) & 0xff) | ((-badinst&1)<<8);
r2 = (badinst >> 16) & 0x1f;
op2 = fixnum_value(SC_REG(scp, r1));
t = (badinst >> 21) & 0x1f;
if (opcode == 0x2d)
res = op1 + op2;
else
res = op1 - op2;
}
else
goto not_interesting;
current_dynamic_space_free_pointer = (lispobj *)SC_REG(scp, reg_ALLOC);
SC_REG(scp, t) = alloc_number(res);
SC_REG(scp, reg_ALLOC)
= (unsigned long)current_dynamic_space_free_pointer;
arch_skip_instruction(scp);
break;
case I_COND:
badinst = *(unsigned long *)(SC_PC(scp)&~3);
if ((badinst&0xfffff800) == (0xb000e000|reg_ALLOC<<21|reg_ALLOC<<16)) {
/* It is an ADDIT,OD i,ALLOC,ALLOC instruction that trapped. */
/* That means that it is the end of a pseudo-atomic. So do the */
/* add stripping off the pseudo-atomic-interrupted bit, and then */
/* tell the machine-independent code to process the pseudo- */
/* atomic. */
int immed = (badinst>>1)&0x3ff;
if (badinst & 1)
immed |= -1<<10;
SC_REG(scp,reg_ALLOC) += (immed-1);
arch_skip_instruction(scp);
interrupt_handle_pending(scp);
break;
}
/* else drop-through. */
default:
#ifdef hpux
interrupt_install_low_level_handler(SIGILL,sigtrap_handler);
#endif
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
interrupt_install_low_level_handler(SIGTRAP,sigtrap_handler);
interrupt_install_low_level_handler(SIGFPE,sigfpe_handler);
}
lispobj funcall0(lispobj function)
{
lispobj *args = current_control_stack_pointer;
return call_into_lisp(function, args, 0);
}
lispobj funcall1(lispobj function, lispobj arg0)
{
lispobj *args = current_control_stack_pointer;
current_control_stack_pointer += 1;
args[0] = arg0;
return call_into_lisp(function, args, 1);
}
lispobj funcall2(lispobj function, lispobj arg0, lispobj arg1)
{
lispobj *args = current_control_stack_pointer;
current_control_stack_pointer += 2;
args[0] = arg0;
args[1] = arg1;
return call_into_lisp(function, args, 2);
}
lispobj funcall3(lispobj function, lispobj arg0, lispobj arg1, lispobj arg2)
{
lispobj *args = current_control_stack_pointer;
current_control_stack_pointer += 3;
args[0] = arg0;
args[1] = arg1;
args[2] = arg2;
return call_into_lisp(function, args, 3);
}