Beispiel #1
0
void
microblaze_pop_frame (struct frame_info *fi)
{
  int rn;
  CORE_ADDR func_addr, func_end, addr;
  enum microblaze_instr op;
  int insn, rd, ra, rb, imm;
  int status;
  char *name;
  int offset = 0;	/* offset that the return instruction specifies */

  /* Find the start and end of this function. */
  /* siva/9/19/05: pop frame was not computing this offset. copied code from
     microblaze_fix_call_dummy to find the return insn & the offset */
  status = find_pc_partial_function (fi->pc, &name, &func_addr, &func_end);

  for (addr = func_addr; addr < func_end; addr += INST_WORD_SIZE) {
	  /* Start decoding the function looking for rtsd */
	  insn = get_insn (addr);
	  op = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);

	  /* Check for return. */
	  if (IS_RETURN(op)) {
		  offset = imm;
		  break; 
	  }
  }

  if (PC_IN_CALL_DUMMY (fi->pc, fi->frame, fi->frame))
    generic_pop_dummy_frame ();
  else
    {
      /* Write out the PC we saved. */
      write_register (PC_REGNUM, FRAME_SAVED_PC (fi) + offset);

      /* Restore any saved registers. */
      for (rn = 0; rn < NUM_REGS; rn++)
	{
	  if (fi->saved_regs[rn] != 0)
	    {
	      ULONGEST value;

	      value = read_memory_unsigned_integer (fi->saved_regs[rn],
						    REGISTER_SIZE);
	      write_register (rn, value);
	    }
	}

      /* Actually cut back the stack. */
      write_register (SP_REGNUM, FRAME_FP (fi));
    }

  /* Finally, throw away any cached frame information. */
  flush_cached_frames ();
}
Beispiel #2
0
static CORE_ADDR
microblaze_analyze_prologue (struct frame_info *fi, CORE_ADDR pc )
{
  CORE_ADDR func_addr, func_end, addr, stop, prologue_end_addr;
  CORE_ADDR stack_size;
  int insn, rn, rd, ra, rb, imm;
  enum microblaze_instr op;
  int status, fp_regnum, flags;
  int framesize;
  int register_offsets[NUM_REGS];
  char *name;
  boolean save_hidden_pointer_found = false;
  boolean non_stack_instruction_found = false;

  /* If provided, use the PC in the frame to look up the
     start of this function. */
  pc = (fi == NULL ? pc : fi->pc);

  /* Find the start of this function. */
  status = find_pc_partial_function (pc, &name, &func_addr, &func_end);

  /* If the start of this function could not be found or if the debbuger
     is stopped at the first instruction of the prologue, do nothing. */
  if (status == 0)
    return pc;

  /* If the debugger is entry function, give up. */
  if (func_addr == entry_point_address ())
    {
      if (fi != NULL)
	fi->extra_info->status |= NO_MORE_FRAMES;
      return pc;
    }

  /* At the start of a function, our frame is in the stack pointer. */
  flags = MY_FRAME_IN_SP;

  /* Start decoding the prologue.  We start by checking two special cases:

     1. We're about to return
     2. We're at the first insn of the prologue.

     If we're about to return, our frame has already been deallocated.
     If we are stopped at the first instruction of a prologue,
     then our frame has not yet been set up. */

  /* Get the first insn from memory */
  microblaze_insn_debug (("MICROBLAZE: starting prologue decoding\n"));
  insn = get_insn (pc);
  microblaze_dump_insn ("got 1: ", pc, insn);
  op = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);

  /* Check for return. */
  if (fi != NULL && IS_RETURN(op))
    {
      microblaze_insn_debug (("MICROBLAZE: got return"));
      if (fi->next == NULL)
	fi->frame = read_sp ();
      fi->extra_info->status = flags;
      return fi->pc;
    }

  /* Check for first insn of prologue */
  if (fi != NULL && fi->pc == func_addr)
    {
      if (fi->next == NULL)
	fi->frame = read_sp ();
      fi->extra_info->status = flags;
      return fi->pc;
    }

  /* Figure out where to stop scanning */
  stop = (fi ? fi->pc : func_end);

  /* Don't walk off the end of the function */
  stop = (stop > func_end ? func_end : stop);

  /* REGISTER_OFFSETS will contain offsets, from the top of the frame
     (NOT the frame pointer), for the various saved registers or -1
     if the register is not saved. */
  for (rn = 0; rn < NUM_REGS; rn++)
    register_offsets[rn] = -1;

  /* Analyze the prologue. Things we determine from analyzing the
     prologue include:
     * the size of the frame
     * where saved registers are located (and which are saved)
     * FP used? */
  microblaze_insn_debug (("MICROBLAZE: Scanning prologue: func_addr=0x%x, stop=0x%x\n",
		     (unsigned int) func_addr, (unsigned int) stop));

  framesize = 0;
  for (prologue_end_addr = addr = func_addr; addr < stop; addr += INST_WORD_SIZE)
    {
      /* Get next insn */
      insn = get_insn (addr);
      microblaze_dump_insn ("got 2: ", addr, insn);
      op = microblaze_decode_insn (insn, &rd, &ra, &rb, &imm);

      /* This code is very sensitive to what functions are present in the prologue. It assumes
	 that the (addi, addik, swi, sw) can be the only instructions in the prologue.
	 */
      if (IS_UPDATE_SP(op, rd, ra))
	{
	  microblaze_insn_debug (("MICROBLAZE: got addi r1,r1,%d; contnuing\n", imm));
	  framesize = -1 * imm; /* Since stack grows towards low memory */
	  save_hidden_pointer_found = false;
	  continue;
	}
      else if (IS_SPILL_SP(op, rd, ra))
	{
	  /* Spill stack pointer */
	  register_offsets[rd] = imm; /* SP spilled before updating */

	  microblaze_insn_debug (("MICROBLAZE: swi r1 r1 %d, continuing\n", imm));
	  save_hidden_pointer_found = false;
	  continue;
	}
      else if (IS_SPILL_REG(op, rd, ra))
	{
	  /* Spill register */
	  register_offsets[rd] = imm - framesize; /* reg spilled after updating */

	  microblaze_insn_debug (("MICROBLAZE: swi %d r1 %d, continuing\n", rd, imm));
	  save_hidden_pointer_found = false;
	  continue;

	}
      else if (IS_ALSO_SPILL_REG(op, rd, ra, rb))
	{
	  /* Spill register */
	  register_offsets[rd] = 0 - framesize; /* reg spilled after updating */

	  microblaze_insn_debug (("MICROBLAZE: sw %d r0 r1, continuing\n", rd));
	  save_hidden_pointer_found = false;
	  continue;

	}
      else if (IS_SETUP_FP(op, ra, rb))
	{
	  /* We have a frame pointer.  Note
	     the register which is acting as the frame pointer. */
	  flags |= MY_FRAME_IN_FP;
	  flags &= ~MY_FRAME_IN_SP;
	  fp_regnum = rd;
	  microblaze_insn_debug (("MICROBLAZE: Found a frame pointer: r%d\n", fp_regnum));
	  save_hidden_pointer_found = false;
	  continue;
	}
      else if (IS_SPILL_REG_FP(op, rd, ra, fp_regnum))
	{
	  register_offsets[rd] = imm - framesize; /* reg spilled after updating */

	  microblaze_insn_debug (("MICROBLAZE: swi %d %d %d, continuing\n", rd, ra, imm));
	  save_hidden_pointer_found = false;
	  continue;
	}
      else if (IS_SAVE_HIDDEN_PTR(op, rd, ra, rb))
	{
	  /* If the first argument is a hidden pointer to the area where the 
	     return structure is to be saved, then it is saved as part of the 
	     prologue */

	  microblaze_insn_debug (("MICROBLAZE: add %d %d %d, continuing\n", rd, ra, rb));
	  save_hidden_pointer_found = true;
	  continue;
	}

      /* as a result of the modification in the next step where we continue to analyze the 
	 prologue till we reach a control flow instruction, we need another variable to store
	 when exactly a non-stack instruction was encountered, which is the current definition
	 of a prologue
       */
      if (!non_stack_instruction_found)
      		prologue_end_addr = addr;
      non_stack_instruction_found = true;

      /* When optimizations are enabled, it is not guaranteed that prologue instructions
	 are not mixed in with other instructions from the program. Some programs show this 
	 behavior at -O2. This can be avoided by adding -fno-schedule-insns2 switch as of now (edk 8.1)
	 In such cases, we scan the function until we see the first control instruction.
       */

	   
      {
	      unsigned op = (unsigned)insn >> 26;

	      if (!(op == 0x26 || op == 0x27 || op == 0x2d || op == 0x2e || op == 0x2f))
		      continue;    /* continue if not control flow (branch, return) */
	      else if (op == 0x2c)
		      continue;    /* continue if imm */
      }

      /* This is not a prologue insn, so stop here. */
      microblaze_insn_debug (("microblaze: insn is not a prologue insn -- ending scan\n"));
      break;
    }

  microblaze_insn_debug (("microblaze: done analyzing prologue\n"));
  microblaze_insn_debug (("microblaze: prologue end = 0x%x\n", addr));

  /* If the last instruction was an add rd, r5, r0 then don't count it as part of
     the prologue */
  if (save_hidden_pointer_found) {
    addr -= INST_WORD_SIZE;
    prologue_end_addr -= INST_WORD_SIZE;
  }

  /* Save everything we have learned about this frame into FI. */
  if (fi != NULL)
    {
      fi->extra_info->framesize = framesize;
      fi->extra_info->fp_regnum = fp_regnum;
      fi->extra_info->status = flags;

      /* Fix the frame pointer. When gcc uses r8 as a frame pointer,
         it is really an arg ptr. We adjust fi->frame to be a "real"
         frame pointer. */
      if (fi->next == NULL)
	{
	  if (fi->extra_info->status & MY_FRAME_IN_SP)
	    fi->frame = read_sp () + framesize;
	  else
	    fi->frame = read_register (fp_regnum) + framesize;
	}

      /* Note where saved registers are stored. The offsets in REGISTER_OFFSETS
         are computed relative to the top of the frame. */
      for (rn = 0; rn < NUM_REGS; rn++)
	{
	  if (register_offsets[rn] != -1)
	    {
	      fi->saved_regs[rn] = fi->frame + register_offsets[rn];
	      microblaze_insn_debug (("Saved register %s stored at 0x%08x, value=0x%08x\n",
			       microblaze_register_names[rn], fi->saved_regs[rn],
				microblaze_read_memory_integer (fi->saved_regs[rn])));
	    }
	}
    }

  /* Return addr of first non-prologue insn. */
  return prologue_end_addr;
}
Beispiel #3
0
// create a trampoline at the given address, that is, we are going to replace
// the original instructions at this particular address. So, in order to
// call the original function from our hook, we have to execute the original
// instructions *before* jumping into addr+offset, where offset is the length
// which totals the size of the instructions which we place in the `tramp'.
// returns 0 on failure, or a positive integer defining the size of the tramp
// NOTE: tramp represents the memory address where the trampoline will be
// placed, copying it to another memory address will result into failure
static int hook_create_trampoline(unsigned char *addr, int len,
	unsigned char *tramp)
{
	addr_map_t addrmap;
	ULONG_PTR target;
	const unsigned char *base = tramp;
	const unsigned char *origaddr = addr;
	unsigned char insnidx = 0;
	int stoleninstrlen = 0;
	cs_insn *insn;

	memset(&addrmap, 0, sizeof(addrmap));

	// our trampoline should contain at least enough bytes to fit the given
	// length
	while (len > 0) {
		insn = get_insn(addr);
		if (insn == NULL)
			goto error;
		int length = insn->size;

		// how many bytes left?
		len -= length;
		stoleninstrlen += length;

		addrmap.map[insnidx][0] = (ULONG_PTR)tramp;
		addrmap.map[insnidx][1] = (ULONG_PTR)addr;

		// check the type of instruction at this particular address, if it's
		// a jump or a call instruction, then we have to calculate some fancy
		// addresses, otherwise we can simply copy the instruction to our
		// trampoline

		if (addr[0] == 0xe8 || addr[0] == 0xe9 || (addr[0] == 0x0f && addr[1] >= 0x80 && addr[1] < 0x90) ||
			((insn->detail->x86.modrm & 0xc7) == 5)) {
			retarget_rip_relative_displacement(&tramp, &addr, insn);
			if (addr[0] == 0xe9 && len > 0)
				goto error;
		}

		else if (addr[0] == 0xeb) {
			target = get_short_rel_target(addr);
			if (addr_is_in_range(target, origaddr, stoleninstrlen))
				target = get_corresponding_tramp_target(&addrmap, target);
			tramp = emit_indirect_jmp(tramp, target);
			addr += length;
			if (len > 0)
				goto error;
		}
		else if (addr[0] == 0xe3 || ((addr[0] & 0xf0) == 0x70)) {
			target = get_short_rel_target(addr);
			if (addr_is_in_range(target, origaddr, stoleninstrlen))
				target = get_corresponding_tramp_target(&addrmap, target);
			tramp = emit_indirect_jcc(addr[0], tramp, target);
			addr += length;
		}
		// return instruction, indicates end of basic block as well, so we
		// have to check if we already have enough space for our hook..
		else if ((addr[0] == 0xc3 || addr[0] == 0xc2) && len > 0) {
			goto error;
		}
		else {
			// copy the instruction directly to the trampoline
			while (length-- != 0) {
				*tramp++ = *addr++;
			}
		}
		put_insn(insn);
	}

	// append a jump from the trampoline to the original function
	*tramp++ = 0xe9;
	emit_rel(tramp, tramp, addr);
	tramp += 4;

	// return the length of this trampoline
	return (int)(tramp - base);
error:
	if (insn)
		put_insn(insn);
	return 0;
}