static void
unwind_regular_code (frame_state_t * fs)
{
  PDSCDEF * pv = PV_FOR (fs->fp);

  ADDR frame_base;

  /* Use the procedure value to unwind, in a way depending on the kind of
     procedure at hand. See ABI-3.3 [Procedure Representation] and ABI-3.4
     [Procedure Types].  */

  if (pv == 0
      || pv->pdsc$w_flags & PDSC$M_BASE_FRAME)
    return;

  frame_base
    = (pv->pdsc$w_flags & PDSC$M_BASE_REG_IS_FP) ? fs->fp : fs->sp;

  switch (pv->pdsc$w_flags & 0xf)
    {
    case PDSC$K_KIND_FP_STACK:
      /* Stack Frame Procedure (ABI-3.4.1). Retrieve the necessary registers
	 from the Register Save Area in the frame.  */
      {
	ADDR rsa_base = frame_base + pv->pdsc$w_rsa_offset;
	int i, j;

	fs->saved_rar = REG_AT (rsa_base);
	fs->saved_pvr = REG_AT (frame_base);

	for (i = 0, j = 0; i < 32; i++)
	  if (pv->pdsc$l_ireg_mask & (1 << i))
	    fs->saved_regs[i] = REG_AT (rsa_base + 8 * ++j);

	/* Note that the loop above is guaranteed to set fs->saved_fpr,
	   because "The preserved register set must always include R29(FP)
	   since it will always be used." (ABI-3.4.3.4 [Register Save Area for
	   All Stack Frames]).

	   Also note that we need to run through all the registers to ensure
	   that unwinding through register procedures (see below) gets the
	   right values out of the saved_regs array.  */
      }
      break;

    case PDSC$K_KIND_FP_REGISTER:
      /* Register Procedure (ABI-3.4.4). Retrieve the necessary registers from
	 the registers where they have been saved.  */
      {
	fs->saved_rar = fs->saved_regs[pv->pdsc$b_save_ra];
	fs->saved_fpr = fs->saved_regs[pv->pdsc$b_save_fp];
      }
      break;

    default:
      /* ??? Are we supposed to ever get here ?  Don't think so.  */
      break;
    }

  /* SP is actually never part of the saved registers area, so we use the
     corresponding entry in the saved_regs array to manually keep track of
     it's evolution.  */
  fs->saved_spr = AS_REG (frame_base) + pv->pdsc$l_size;
}
Example #2
0
static void
unwind_kernel_handler (frame_state_t * fs)
{
  PDSCDEF * pv = PV_FOR (fs->fp);

  CHFDEF1 *sigargs;
  CHFDEF2 *mechargs;

  /* Retrieve the arguments passed to the handler, by way of a VMS service
     providing the corresponding "Invocation Context Block".  */
  {
    long handler_ivhandle;
    INVO_CONTEXT_BLK handler_ivcb;

    CHFCTX *chfctx;

    handler_ivcb.libicb$q_ireg [29] = AS_REG (fs->fp);
    handler_ivcb.libicb$q_ireg [30] = 0;

    handler_ivhandle = LIB$GET_INVO_HANDLE (&handler_ivcb);

    if ((LIB$GET_INVO_CONTEXT (handler_ivhandle, &handler_ivcb) & 1) != 1)
      return;

    chfctx = (CHFCTX *) AS_ADDR (handler_ivcb.libicb$ph_chfctx_addr);

    sigargs = (CHFDEF1 *) AS_ADDR (chfctx->chfctx$q_sigarglst);
    mechargs = (CHFDEF2 *) AS_ADDR (chfctx->chfctx$q_mcharglst);
  }

  /* Compute the saved return address as the PC of the instruction causing the
     condition, accounting for the fact that it will be adjusted by the next
     call to "unwind" as if it was an actual call return address.  */
  {
    /* ABI-6.5.1.1 [Signal Argument Vector]: The signal occurrence address
       is available from the sigargs argument to the handler, designed to
       support both 32 and 64 bit addresses.  The initial reference we get
       is a pointer to the 32bit form, from which one may extract a pointer
       to the 64bit version if need be.  We work directly from the 32bit
       form here.  */

    /* The sigargs vector structure for 32bits addresses is:

       <......32bit......>
       +-----------------+
       |      Vsize      | :chf$is_sig_args
       +-----------------+ -+-
       | Condition Value |  : [0]
       +-----------------+  :
       |       ...       |  :
       +-----------------+  : vector of Vsize entries
       |    Signal PC    |  :
       +-----------------+  :
       |       PS        |  : [Vsize - 1]
       +-----------------+ -+-

       */

    unsigned long * sigargs_vector
      = ((unsigned long *) (&sigargs->chf$is_sig_args)) + 1;

    long sigargs_vsize
      = sigargs->chf$is_sig_args;

    fs->saved_rar = (REG) sigargs_vector [sigargs_vsize - 2] + PC_ADJUST;
  }

  fs->saved_spr = RA_UNKNOWN;
  fs->saved_fpr = (REG) mechargs->chf$q_mch_frame;
  fs->saved_pvr = (REG) mechargs->chf$q_mch_savr27;

  fs->saved_regs[16] = (REG) mechargs->chf$q_mch_savr16;
  fs->saved_regs[17] = (REG) mechargs->chf$q_mch_savr17;
  fs->saved_regs[18] = (REG) mechargs->chf$q_mch_savr18;
  fs->saved_regs[19] = (REG) mechargs->chf$q_mch_savr19;
  fs->saved_regs[20] = (REG) mechargs->chf$q_mch_savr20;
}