예제 #1
0
static void
pex64_xdata_print_uwd_codes (FILE *file, struct pex64_unwind_info *ui,
			     bfd_vma pc_addr)
{
  bfd_vma i;
  bfd_vma tmp = 0;
  const bfd_byte *insns[256];
  bfd_vma insns_count = 0;
  const bfd_byte *dta = ui->rawUnwindCodes;

  if (ui->CountOfCodes == 0 || !dta)
    return;

  /* Sort array ascending. Note: it is stored in reversed order.  */
  for (i = 0; i < ui->CountOfCodes; i++)
    {
      const bfd_byte *t;

      t = insns[insns_count++] = &dta[i * 2];
      switch (PEX64_UNWCODE_CODE (t[1]))
	{
	case UWOP_PUSH_NONVOL:
	case UWOP_ALLOC_SMALL:
	case UWOP_SET_FPREG:
	case UWOP_PUSH_MACHFRAME:
	  break;
	case UWOP_ALLOC_LARGE:
	  if (PEX64_UNWCODE_INFO (t[1]) == 0)
	    {
	      i += 1;
	      break;
	    }
	  else if (PEX64_UNWCODE_INFO (t[1]) == 1)
	    {
	      i += 2;
	      break;
	    }
	  /* fall through.  */
	default:
	  fprintf (file, "\t contains unknown code (%u).\n",
		   (unsigned int) PEX64_UNWCODE_CODE (t[1]));
	  return;
	case UWOP_SAVE_NONVOL:
	case UWOP_SAVE_XMM:
	case UWOP_SAVE_XMM128:
	  i++;
	  break;
	case UWOP_SAVE_NONVOL_FAR:
	case UWOP_SAVE_XMM_FAR:
	case UWOP_SAVE_XMM128_FAR:
	  i += 2;
	  break;
	}
    }
  fprintf (file, "\t At pc 0x");
  fprintf_vma (file, pc_addr);
  fprintf (file, " there are the following saves (in logical order).\n");
  for (i = insns_count; i > 0;)
    {
      --i;
      dta = insns[i];
      fprintf (file, "\t  insn ends at pc+0x%02x: ", (unsigned int) dta[0]);
      switch (PEX64_UNWCODE_CODE (dta[1]))
	{
	case UWOP_PUSH_NONVOL:
	  fprintf (file, "push %s.\n", pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
	  break;
	case UWOP_ALLOC_LARGE:
	  if (PEX64_UNWCODE_INFO (dta[1]) == 0)
	    {
	      tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
	      tmp *= 8;
	    }
	  else
	    tmp = (bfd_vma) (*((unsigned int *)&dta[2]));
	  fprintf (file, "save stack region of size 0x");
	  fprintf_vma (file, tmp);
	  fprintf (file,".\n");
	  break;
	case UWOP_ALLOC_SMALL:
	  tmp = (bfd_vma) PEX64_UNWCODE_INFO (dta[1]);
	  tmp += 1;
	  tmp *= 8;
	  fprintf (file, "save stack region of size 0x");
	  fprintf_vma (file, tmp);
	  fprintf (file,".\n");
	  break;
	case UWOP_SET_FPREG:
	  tmp = (bfd_vma) PEX64_UNWCODE_INFO (dta[1]);
	  tmp *= 16;
	  fprintf (file, "FPReg = (FrameReg) + 0x");
	  fprintf_vma (file, tmp);
	  fprintf (file, ".\n");
	  break;
	case UWOP_SAVE_NONVOL:
	  fprintf (file, "mov %s at 0x",
		   pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
	  tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
	  tmp *= 8;
	  fprintf_vma (file, tmp);
	  fprintf (file, ".\n");
	  break;
	case UWOP_SAVE_NONVOL_FAR:
	  fprintf (file, "mov %s at 0x",
		   pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
	  tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
	  fprintf_vma (file, tmp);
	  fprintf (file, ".\n");
	  break;
	case UWOP_SAVE_XMM:
	  tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
	  tmp *= 8;
	  fprintf (file, "mov mm%u at 0x",
		   (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
	  fprintf_vma (file, tmp);
	  fprintf (file, ".\n");
	  break;
	case UWOP_SAVE_XMM_FAR:
	  tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
	  fprintf (file, "mov mm%u at 0x",
		   (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
	  fprintf_vma (file, tmp);
	  fprintf (file, ".\n");
	  break;
	case UWOP_SAVE_XMM128:
	  tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
	  tmp *= 16;
	  fprintf (file, "mov xmm%u at 0x",
		   (unsigned int) PEX64_UNWCODE_INFO ( dta[1]));
	  fprintf_vma (file, tmp);
	  fprintf (file, ".\n");
	  break;
	case UWOP_SAVE_XMM128_FAR:
	  tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
	  fprintf (file, "mov xmm%u at 0x",
		   (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
	  fprintf_vma (file, tmp);
	  fprintf (file, ".\n");
	  break;
	case UWOP_PUSH_MACHFRAME:
	  fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
	  if (PEX64_UNWCODE_INFO (dta[1]) == 0)
	    {
	      fprintf (file, ")");
	    }
	  else if (PEX64_UNWCODE_INFO (dta[1]) == 1)
	    {
	      fprintf (file, ",ErrorCode)");
	    }
	  else
	    fprintf (file, ", unknown(%u))",
		     (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
	  fprintf (file,".\n");
	  break;
	default:
	  fprintf (file, "unknown code %u.\n",
		   (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
	  break;
      }
    }
}
예제 #2
0
static void
pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
			     struct pex64_unwind_info *ui,
			     struct pex64_runtime_function *rf)
{
  unsigned int i;
  unsigned int tmp; /* At least 32 bits.  */
  int save_allowed;

  if (ui->CountOfCodes == 0 || ui->rawUnwindCodes == NULL)
    return;

  /* According to UNWIND_CODE documentation:
      If an FP reg is used, the any unwind code taking an offset must only be
      used after the FP reg is established in the prolog.
     But there are counter examples of that in system dlls...  */
  save_allowed = TRUE;

  i = 0;

  if (ui->Version == 2
      && PEX64_UNWCODE_CODE (ui->rawUnwindCodes[1]) == UWOP_EPILOG)
    {
      /* Display epilog opcode (whose docoding is not fully documented).
         Looks to be designed to speed-up unwinding, as there is no need
	 to decode instruction flow if outside an epilog.  */
      unsigned int func_size = rf->rva_EndAddress - rf->rva_BeginAddress;

      fprintf (file, "\tv2 epilog (length: %02x) at pc+:",
	       ui->rawUnwindCodes[0]);
      if (PEX64_UNWCODE_INFO (ui->rawUnwindCodes[1]))
	fprintf (file, " 0x%x", func_size - ui->rawUnwindCodes[0]);
      i++;
      for (; i < ui->CountOfCodes; i++)
	{
	  const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
	  unsigned int off;

	  if (PEX64_UNWCODE_CODE (dta[1]) != UWOP_EPILOG)
	    break;
	  off = dta[0] | (PEX64_UNWCODE_INFO (dta[1]) << 8);
	  if (off == 0)
	    fprintf (file, " [pad]");
	  else
	    fprintf (file, " 0x%x", func_size - off);
	}
      fputc ('\n', file);
    }

  for (; i < ui->CountOfCodes; i++)
    {
      const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
      unsigned int info = PEX64_UNWCODE_INFO (dta[1]);
      int unexpected = FALSE;

      fprintf (file, "\t  pc+0x%02x: ", (unsigned int) dta[0]);
      switch (PEX64_UNWCODE_CODE (dta[1]))
	{
	case UWOP_PUSH_NONVOL:
	  fprintf (file, "push %s", pex_regs[info]);
	  break;
	case UWOP_ALLOC_LARGE:
	  if (info == 0)
	    {
	      tmp = bfd_get_16 (abfd, &dta[2]) * 8;
	      i++;
	    }
	  else
	    {
	      tmp = bfd_get_32 (abfd, &dta[2]);
	      i += 2;
	    }
	  fprintf (file, "alloc large area: rsp = rsp - 0x%x", tmp);
	  break;
	case UWOP_ALLOC_SMALL:
	  fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
	  break;
	case UWOP_SET_FPREG:
	  /* According to the documentation, info field is unused.  */
	  fprintf (file, "FPReg: %s = rsp + 0x%x (info = 0x%x)",
		   pex_regs[ui->FrameRegister],
		   (unsigned int) ui->FrameOffset * 16, info);
	  unexpected = ui->FrameRegister == 0;
	  save_allowed = FALSE;
	  break;
	case UWOP_SAVE_NONVOL:
	  tmp = bfd_get_16 (abfd, &dta[2]) * 8;
	  i++;
	  fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
	  unexpected = !save_allowed;
	  break;
	case UWOP_SAVE_NONVOL_FAR:
	  tmp = bfd_get_32 (abfd, &dta[2]);
	  i += 2;
	  fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
	  unexpected = !save_allowed;
	  break;
	case UWOP_SAVE_XMM:
	  if (ui->Version == 1)
	    {
	      tmp = bfd_get_16 (abfd, &dta[2]) * 8;
	      i++;
	      fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
	      unexpected = !save_allowed;
	    }
	  else if (ui->Version == 2)
	    {
	      fprintf (file, "epilog %02x %01x", dta[0], info);
	      unexpected = TRUE;
	    }
	  break;
	case UWOP_SAVE_XMM_FAR:
	  tmp = bfd_get_32 (abfd, &dta[2]) * 8;
	  i += 2;
	  fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
	  unexpected = !save_allowed;
	  break;
	case UWOP_SAVE_XMM128:
	  tmp = bfd_get_16 (abfd, &dta[2]) * 16;
	  i++;
	  fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
	  unexpected = !save_allowed;
	  break;
	case UWOP_SAVE_XMM128_FAR:
	  tmp = bfd_get_32 (abfd, &dta[2]) * 16;
	  i += 2;
	  fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
	  unexpected = !save_allowed;
	  break;
	case UWOP_PUSH_MACHFRAME:
	  fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
	  if (info == 0)
	    fprintf (file, ")");
	  else if (info == 1)
	    fprintf (file, ",ErrorCode)");
	  else
	    fprintf (file, ", unknown(%u))", info);
	  break;
	default:
	  /* PR 17512: file: 2245-7442-0.004.  */
	  fprintf (file, _("Unknown: %x"), PEX64_UNWCODE_CODE (dta[1]));
	  break;
      }
      if (unexpected)
	fprintf (file, " [Unexpected!]");
      fputc ('\n', file);
    }
}
예제 #3
0
static void
amd64_windows_frame_decode_insns (struct frame_info *this_frame,
				  struct amd64_windows_frame_cache *cache,
				  CORE_ADDR unwind_info)
{
  CORE_ADDR save_addr = 0;
  CORE_ADDR cur_sp = cache->sp;
  struct gdbarch *gdbarch = get_frame_arch (this_frame);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  int j;

  for (j = 0; ; j++)
    {
      struct external_pex64_unwind_info ex_ui;
      /* There are at most 256 16-bit unwind insns.  */
      gdb_byte insns[2 * 256];
      gdb_byte *p;
      gdb_byte *end_insns;
      unsigned char codes_count;
      unsigned char frame_reg;
      unsigned char frame_off;

      /* Read and decode header.  */
      if (target_read_memory (cache->image_base + unwind_info,
			      (gdb_byte *) &ex_ui, sizeof (ex_ui)) != 0)
	return;

      if (frame_debug)
	fprintf_unfiltered
	  (gdb_stdlog,
	   "amd64_windows_frame_decodes_insn: "
	   "%s: ver: %02x, plgsz: %02x, cnt: %02x, frame: %02x\n",
	   paddress (gdbarch, unwind_info),
	   ex_ui.Version_Flags, ex_ui.SizeOfPrologue,
	   ex_ui.CountOfCodes, ex_ui.FrameRegisterOffset);

      /* Check version.  */
      if (PEX64_UWI_VERSION (ex_ui.Version_Flags) != 1
	  && PEX64_UWI_VERSION (ex_ui.Version_Flags) != 2)
	return;

      if (j == 0
	  && (cache->pc >=
	      cache->image_base + cache->start_rva + ex_ui.SizeOfPrologue))
	{
	  /* Not in the prologue.  We want to detect if the PC points to an
	     epilogue. If so, the epilogue detection+decoding function is
	     sufficient.  Otherwise, the unwinder will consider that the PC
	     is in the body of the function and will need to decode unwind
	     info.  */
	  if (amd64_windows_frame_decode_epilogue (this_frame, cache) == 1)
	    return;

	  /* Not in an epilog.  Clear possible side effects.  */
	  memset (cache->prev_reg_addr, 0, sizeof (cache->prev_reg_addr));
	}

      codes_count = ex_ui.CountOfCodes;
      frame_reg = PEX64_UWI_FRAMEREG (ex_ui.FrameRegisterOffset);

      if (frame_reg != 0)
	{
	  /* According to msdn:
	     If an FP reg is used, then any unwind code taking an offset must
	     only be used after the FP reg is established in the prolog.  */
	  gdb_byte buf[8];
	  int frreg = amd64_windows_w2gdb_regnum[frame_reg];

	  get_frame_register (this_frame, frreg, buf);
	  save_addr = extract_unsigned_integer (buf, 8, byte_order);

	  if (frame_debug)
	    fprintf_unfiltered (gdb_stdlog, "   frame_reg=%s, val=%s\n",
				gdbarch_register_name (gdbarch, frreg),
				paddress (gdbarch, save_addr));
	}

      /* Read opcodes.  */
      if (codes_count != 0
	  && target_read_memory (cache->image_base + unwind_info
				 + sizeof (ex_ui),
				 insns, codes_count * 2) != 0)
	return;

      end_insns = &insns[codes_count * 2];
      p = insns;

      /* Skip opcodes 6 of version 2.  This opcode is not documented.  */
      if (PEX64_UWI_VERSION (ex_ui.Version_Flags) == 2)
	{
	  for (; p < end_insns; p += 2)
	    if (PEX64_UNWCODE_CODE (p[1]) != 6)
	      break;
	}

      for (; p < end_insns; p += 2)
	{
	  int reg;

	  if (frame_debug)
	    fprintf_unfiltered
	      (gdb_stdlog, "   op #%u: off=0x%02x, insn=0x%02x\n",
	       (unsigned) (p - insns), p[0], p[1]);

	  /* Virtually execute the operation.  */
	  if (cache->pc >= cache->image_base + cache->start_rva + p[0])
	    {
	      /* If there is no frame registers defined, the current value of
		 rsp is used instead.  */
	      if (frame_reg == 0)
		save_addr = cur_sp;

	      switch (PEX64_UNWCODE_CODE (p[1]))
		{
		case UWOP_PUSH_NONVOL:
		  /* Push pre-decrements RSP.  */
		  reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])];
		  cache->prev_reg_addr[reg] = cur_sp;
		  cur_sp += 8;
		  break;
		case UWOP_ALLOC_LARGE:
		  if (PEX64_UNWCODE_INFO (p[1]) == 0)
		    cur_sp +=
		      8 * extract_unsigned_integer (p + 2, 2, byte_order);
		  else if (PEX64_UNWCODE_INFO (p[1]) == 1)
		    cur_sp += extract_unsigned_integer (p + 2, 4, byte_order);
		  else
		    return;
		  break;
		case UWOP_ALLOC_SMALL:
		  cur_sp += 8 + 8 * PEX64_UNWCODE_INFO (p[1]);
		  break;
		case UWOP_SET_FPREG:
		  cur_sp = save_addr
		    - PEX64_UWI_FRAMEOFF (ex_ui.FrameRegisterOffset) * 16;
		  break;
		case UWOP_SAVE_NONVOL:
		  reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])];
		  cache->prev_reg_addr[reg] = save_addr
		    - 8 * extract_unsigned_integer (p + 2, 2, byte_order);
		  break;
		case UWOP_SAVE_NONVOL_FAR:
		  reg = amd64_windows_w2gdb_regnum[PEX64_UNWCODE_INFO (p[1])];
		  cache->prev_reg_addr[reg] = save_addr
		    - 8 * extract_unsigned_integer (p + 2, 4, byte_order);
		  break;
		case UWOP_SAVE_XMM128:
		  cache->prev_xmm_addr[PEX64_UNWCODE_INFO (p[1])] =
		    save_addr
		    - 16 * extract_unsigned_integer (p + 2, 2, byte_order);
		  break;
		case UWOP_SAVE_XMM128_FAR:
		  cache->prev_xmm_addr[PEX64_UNWCODE_INFO (p[1])] =
		    save_addr
		    - 16 * extract_unsigned_integer (p + 2, 4, byte_order);
		  break;
		case UWOP_PUSH_MACHFRAME:
		  if (PEX64_UNWCODE_INFO (p[1]) == 0)
		    {
		      cache->prev_rip_addr = cur_sp + 0;
		      cache->prev_rsp_addr = cur_sp + 24;
		      cur_sp += 40;
		    }
		  else if (PEX64_UNWCODE_INFO (p[1]) == 1)
		    {
		      cache->prev_rip_addr = cur_sp + 8;
		      cache->prev_rsp_addr = cur_sp + 32;
		      cur_sp += 48;
		    }
		  else
		    return;
		  break;
		default:
		  return;
		}
	    }

	  /* Adjust with the length of the opcode.  */
	  switch (PEX64_UNWCODE_CODE (p[1]))
	    {
	    case UWOP_PUSH_NONVOL:
	    case UWOP_ALLOC_SMALL:
	    case UWOP_SET_FPREG:
	    case UWOP_PUSH_MACHFRAME:
	      break;
	    case UWOP_ALLOC_LARGE:
	      if (PEX64_UNWCODE_INFO (p[1]) == 0)
		p += 2;
	      else if (PEX64_UNWCODE_INFO (p[1]) == 1)
		p += 4;
	      else
		return;
	      break;
	    case UWOP_SAVE_NONVOL:
	    case UWOP_SAVE_XMM128:
	      p += 2;
	      break;
	    case UWOP_SAVE_NONVOL_FAR:
	    case UWOP_SAVE_XMM128_FAR:
	      p += 4;
	      break;
	    default:
	      return;
	    }
	}
      if (PEX64_UWI_FLAGS (ex_ui.Version_Flags) != UNW_FLAG_CHAININFO)
	break;
      else
	{
	  /* Read the chained unwind info.  */
	  struct external_pex64_runtime_function d;
	  CORE_ADDR chain_vma;

	  chain_vma = cache->image_base + unwind_info
	    + sizeof (ex_ui) + ((codes_count + 1) & ~1) * 2;

	  if (target_read_memory (chain_vma, (gdb_byte *) &d, sizeof (d)) != 0)
	    return;

	  cache->start_rva =
	    extract_unsigned_integer (d.rva_BeginAddress, 4, byte_order);
	  cache->end_rva =
	    extract_unsigned_integer (d.rva_EndAddress, 4, byte_order);
	  unwind_info =
	    extract_unsigned_integer (d.rva_UnwindData, 4, byte_order);

	  if (frame_debug)
	    fprintf_unfiltered
	      (gdb_stdlog,
	       "amd64_windows_frame_decodes_insn (next in chain):"
	       " unwind_data=%s, start_rva=%s, end_rva=%s\n",
	       paddress (gdbarch, unwind_info),
	       paddress (gdbarch, cache->start_rva),
	       paddress (gdbarch, cache->end_rva));
	}

      /* Allow the user to break this loop.  */
      QUIT;
    }
  /* PC is saved by the call.  */
  if (cache->prev_rip_addr == 0)
    cache->prev_rip_addr = cur_sp;
  cache->prev_sp = cur_sp + 8;

  if (frame_debug)
    fprintf_unfiltered (gdb_stdlog, "   prev_sp: %s, prev_pc @%s\n",
			paddress (gdbarch, cache->prev_sp),
			paddress (gdbarch, cache->prev_rip_addr));
}