Пример #1
0
static CORE_ADDR
arm_symbian_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
  struct gdbarch *gdbarch;
  enum bfd_endian byte_order;
  ULONGEST insn;
  CORE_ADDR dest;
  gdb_byte buf[4];

  if (!in_plt_section (pc))
    return 0;

  if (target_read_memory (pc, buf, 4) != 0)
    return 0;

  gdbarch = get_frame_arch (frame);
  byte_order = gdbarch_byte_order (gdbarch);

  /* ldr pc, [pc, #-4].  */
  insn = extract_unsigned_integer (buf, 4, byte_order);
  if (insn != 0xe51ff004)
    return 0;

  if (target_read_memory (pc + 4, buf, 4) != 0)
    return 0;

  dest = extract_unsigned_integer (buf, 4, byte_order);
  return gdbarch_addr_bits_remove (gdbarch, dest);
}
Пример #2
0
static void
arm_supply_gregset (struct regcache *regcache, struct reg *gregset)
{
  int regno;
  CORE_ADDR r_pc;

  /* Integer registers.  */
  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
    regcache_raw_supply (regcache, regno, (char *) &gregset->r[regno]);

  regcache_raw_supply (regcache, ARM_SP_REGNUM,
		       (char *) &gregset->r_sp);
  regcache_raw_supply (regcache, ARM_LR_REGNUM,
		       (char *) &gregset->r_lr);
  /* This is ok: we're running native...  */
  r_pc = gdbarch_addr_bits_remove (get_regcache_arch (regcache), gregset->r_pc);
  regcache_raw_supply (regcache, ARM_PC_REGNUM, (char *) &r_pc);

  if (arm_apcs_32)
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
			 (char *) &gregset->r_cpsr);
  else
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
			 (char *) &gregset->r_pc);
}
Пример #3
0
static void
fetch_regs (struct regcache *regcache)
{
  int ret, regno, tid;
  elf_gregset_t regs;

  /* Get the thread id for the ptrace call.  */
  tid = GET_THREAD_ID (inferior_ptid);
  
  ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);
  if (ret < 0)
    {
      warning (_("Unable to fetch general registers."));
      return;
    }

  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
    regcache_raw_supply (regcache, regno, (char *) &regs[regno]);

  if (arm_apcs_32)
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
			 (char *) &regs[ARM_CPSR_GREGNUM]);
  else
    regcache_raw_supply (regcache, ARM_PS_REGNUM,
			 (char *) &regs[ARM_PC_REGNUM]);

  regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
			  (get_regcache_arch (regcache), regs[ARM_PC_REGNUM]);
  regcache_raw_supply (regcache, ARM_PC_REGNUM,
		       (char *) &regs[ARM_PC_REGNUM]);
}
Пример #4
0
static void
store_regs (const struct regcache *regcache)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  struct reg inferior_registers;
  int ret;
  int regno;


  for (regno = ARM_A1_REGNUM; regno < ARM_SP_REGNUM; regno++)
    regcache_raw_collect (regcache, regno,
			  (char *) &inferior_registers.r[regno]);

  regcache_raw_collect (regcache, ARM_SP_REGNUM,
			(char *) &inferior_registers.r_sp);
  regcache_raw_collect (regcache, ARM_LR_REGNUM,
			(char *) &inferior_registers.r_lr);

  if (arm_apcs_32)
    {
      regcache_raw_collect (regcache, ARM_PC_REGNUM,
			    (char *) &inferior_registers.r_pc);
      regcache_raw_collect (regcache, ARM_PS_REGNUM,
			    (char *) &inferior_registers.r_cpsr);
    }
  else
    {
      unsigned pc_val;
      unsigned psr_val;

      regcache_raw_collect (regcache, ARM_PC_REGNUM,
			    (char *) &pc_val);
      regcache_raw_collect (regcache, ARM_PS_REGNUM,
			    (char *) &psr_val);
	  
      pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val);
      psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val);

      inferior_registers.r_pc = pc_val | psr_val;
    }

  ret = ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
		(PTRACE_TYPE_ARG3) &inferior_registers, 0);

  if (ret < 0)
    warning (_("unable to store general registers"));
}
Пример #5
0
static void
fetch_register (struct regcache *regcache, int regno)
{
  struct reg inferior_registers;
  int ret;

  ret = ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
		(PTRACE_TYPE_ARG3) &inferior_registers, 0);

  if (ret < 0)
    {
      warning (_("unable to fetch general register"));
      return;
    }

  switch (regno)
    {
    case ARM_SP_REGNUM:
      regcache_raw_supply (regcache, ARM_SP_REGNUM,
			   (char *) &inferior_registers.r_sp);
      break;

    case ARM_LR_REGNUM:
      regcache_raw_supply (regcache, ARM_LR_REGNUM,
			   (char *) &inferior_registers.r_lr);
      break;

    case ARM_PC_REGNUM:
      /* This is ok: we're running native...  */
      inferior_registers.r_pc = gdbarch_addr_bits_remove
				  (get_regcache_arch (regcache),
				   inferior_registers.r_pc);
      regcache_raw_supply (regcache, ARM_PC_REGNUM,
			   (char *) &inferior_registers.r_pc);
      break;

    case ARM_PS_REGNUM:
      if (arm_apcs_32)
	regcache_raw_supply (regcache, ARM_PS_REGNUM,
			     (char *) &inferior_registers.r_cpsr);
      else
	regcache_raw_supply (regcache, ARM_PS_REGNUM,
			     (char *) &inferior_registers.r_pc);
      break;

    default:
      regcache_raw_supply (regcache, regno,
			   (char *) &inferior_registers.r[regno]);
      break;
    }
}
Пример #6
0
static void
fetch_register (struct regcache *regcache, int regno)
{
  int ret, tid;
  elf_gregset_t regs;

  /* Get the thread id for the ptrace call.  */
  tid = GET_THREAD_ID (inferior_ptid);

  if (have_ptrace_getregset == TRIBOOL_TRUE)
    {
      struct iovec iov;

      iov.iov_base = &regs;
      iov.iov_len = sizeof (regs);

      ret = ptrace (PTRACE_GETREGSET, tid, NT_PRSTATUS, &iov);
    }
  else
    ret = ptrace (PTRACE_GETREGS, tid, 0, &regs);

  if (ret < 0)
    {
      warning (_("Unable to fetch general register."));
      return;
    }

  if (regno >= ARM_A1_REGNUM && regno < ARM_PC_REGNUM)
    regcache_raw_supply (regcache, regno, (char *) &regs[regno]);

  if (ARM_PS_REGNUM == regno)
    {
      if (arm_apcs_32)
        regcache_raw_supply (regcache, ARM_PS_REGNUM,
			     (char *) &regs[ARM_CPSR_GREGNUM]);
      else
        regcache_raw_supply (regcache, ARM_PS_REGNUM,
			     (char *) &regs[ARM_PC_REGNUM]);
    }
    
  if (ARM_PC_REGNUM == regno)
    { 
      regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
			      (get_regcache_arch (regcache),
			       regs[ARM_PC_REGNUM]);
      regcache_raw_supply (regcache, ARM_PC_REGNUM,
			   (char *) &regs[ARM_PC_REGNUM]);
    }
}
Пример #7
0
static void
arm_linux_restart_syscall_init (const struct tramp_frame *self,
				struct frame_info *this_frame,
				struct trad_frame_cache *this_cache,
				CORE_ADDR func)
{
  struct gdbarch *gdbarch = get_frame_arch (this_frame);
  CORE_ADDR sp = get_frame_register_unsigned (this_frame, ARM_SP_REGNUM);
  CORE_ADDR pc = get_frame_memory_unsigned (this_frame, sp, 4);
  CORE_ADDR cpsr = get_frame_register_unsigned (this_frame, ARM_PS_REGNUM);
  ULONGEST t_bit = arm_psr_thumb_bit (gdbarch);
  int sp_offset;

  /* There are two variants of this trampoline; with older kernels, the
     stub is placed on the stack, while newer kernels use the stub from
     the vector page.  They are identical except that the older version
     increments SP by 12 (to skip stored PC and the stub itself), while
     the newer version increments SP only by 4 (just the stored PC).  */
  if (self->insn[1].bytes == ARM_LDR_PC_SP_4)
    sp_offset = 4;
  else
    sp_offset = 12;

  /* Update Thumb bit in CPSR.  */
  if (pc & 1)
    cpsr |= t_bit;
  else
    cpsr &= ~t_bit;

  /* Remove Thumb bit from PC.  */
  pc = gdbarch_addr_bits_remove (gdbarch, pc);

  /* Save previous register values.  */
  trad_frame_set_reg_value (this_cache, ARM_SP_REGNUM, sp + sp_offset);
  trad_frame_set_reg_value (this_cache, ARM_PC_REGNUM, pc);
  trad_frame_set_reg_value (this_cache, ARM_PS_REGNUM, cpsr);

  /* Save a frame ID.  */
  trad_frame_set_id (this_cache, frame_id_build (sp, func));
}
Пример #8
0
void
aarch32_gp_regcache_supply (struct regcache *regcache, uint32_t *regs,
			    int arm_apcs_32)
{
  int regno;

  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
    regcache->raw_supply (regno, &regs[regno]);

  if (arm_apcs_32)
    {
      /* Clear reserved bits bit 20 to bit 23.  */
      regs[ARM_CPSR_GREGNUM] &= 0xff0fffff;
      regcache->raw_supply (ARM_PS_REGNUM, &regs[ARM_CPSR_GREGNUM]);
    }
  else
    regcache->raw_supply (ARM_PS_REGNUM, &regs[ARM_PC_REGNUM]);

  regs[ARM_PC_REGNUM] = gdbarch_addr_bits_remove
			  (regcache->arch (), regs[ARM_PC_REGNUM]);
  regcache->raw_supply (ARM_PC_REGNUM, &regs[ARM_PC_REGNUM]);
}
Пример #9
0
void
arm_linux_supply_gregset (const struct regset *regset,
			  struct regcache *regcache,
			  int regnum, const void *gregs_buf, size_t len)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
  const gdb_byte *gregs = gregs_buf;
  int regno;
  CORE_ADDR reg_pc;
  gdb_byte pc_buf[INT_REGISTER_SIZE];

  for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++)
    if (regnum == -1 || regnum == regno)
      regcache_raw_supply (regcache, regno,
			   gregs + INT_REGISTER_SIZE * regno);

  if (regnum == ARM_PS_REGNUM || regnum == -1)
    {
      if (arm_apcs_32)
	regcache_raw_supply (regcache, ARM_PS_REGNUM,
			     gregs + INT_REGISTER_SIZE * ARM_CPSR_GREGNUM);
      else
	regcache_raw_supply (regcache, ARM_PS_REGNUM,
			     gregs + INT_REGISTER_SIZE * ARM_PC_REGNUM);
    }

  if (regnum == ARM_PC_REGNUM || regnum == -1)
    {
      reg_pc = extract_unsigned_integer (gregs
					 + INT_REGISTER_SIZE * ARM_PC_REGNUM,
					 INT_REGISTER_SIZE, byte_order);
      reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc);
      store_unsigned_integer (pc_buf, INT_REGISTER_SIZE, byte_order, reg_pc);
      regcache_raw_supply (regcache, ARM_PC_REGNUM, pc_buf);
    }
}
Пример #10
0
static void
som_symtab_read (bfd *abfd, struct objfile *objfile,
		 struct section_offsets *section_offsets)
{
  struct cleanup *cleanup;
  struct gdbarch *gdbarch = get_objfile_arch (objfile);
  unsigned int number_of_symbols;
  int val, dynamic;
  char *stringtab;
  asection *shlib_info;
  struct som_external_symbol_dictionary_record *buf, *bufp, *endbufp;
  char *symname;
  CONST int symsize = sizeof (struct som_external_symbol_dictionary_record);


#define text_offset ANOFFSET (section_offsets, SECT_OFF_TEXT (objfile))
#define data_offset ANOFFSET (section_offsets, SECT_OFF_DATA (objfile))

  number_of_symbols = bfd_get_symcount (abfd);

  /* Allocate a buffer to read in the debug info.
     We avoid using alloca because the memory size could be so large
     that we could hit the stack size limit.  */
  buf = xmalloc (symsize * number_of_symbols);
  cleanup = make_cleanup (xfree, buf);
  bfd_seek (abfd, obj_som_sym_filepos (abfd), SEEK_SET);
  val = bfd_bread (buf, symsize * number_of_symbols, abfd);
  if (val != symsize * number_of_symbols)
    error (_("Couldn't read symbol dictionary!"));

  /* Allocate a buffer to read in the som stringtab section of
     the debugging info.  Again, we avoid using alloca because
     the data could be so large that we could potentially hit
     the stack size limitat.  */
  stringtab = xmalloc (obj_som_stringtab_size (abfd));
  make_cleanup (xfree, stringtab);
  bfd_seek (abfd, obj_som_str_filepos (abfd), SEEK_SET);
  val = bfd_bread (stringtab, obj_som_stringtab_size (abfd), abfd);
  if (val != obj_som_stringtab_size (abfd))
    error (_("Can't read in HP string table."));

  /* We need to determine if objfile is a dynamic executable (so we
     can do the right thing for ST_ENTRY vs ST_CODE symbols).

     There's nothing in the header which easily allows us to do
     this.

     This code used to rely upon the existence of a $SHLIB_INFO$
     section to make this determination.  HP claims that it is
     more accurate to check for a nonzero text offset, but they
     have not provided any information about why that test is
     more accurate.  */
  dynamic = (text_offset != 0);

  endbufp = buf + number_of_symbols;
  for (bufp = buf; bufp < endbufp; ++bufp)
    {
      enum minimal_symbol_type ms_type;
      unsigned int flags = bfd_getb32 (bufp->flags);
      unsigned int symbol_type
	= (flags >> SOM_SYMBOL_TYPE_SH) & SOM_SYMBOL_TYPE_MASK;
      unsigned int symbol_scope
	= (flags >> SOM_SYMBOL_SCOPE_SH) & SOM_SYMBOL_SCOPE_MASK;
      CORE_ADDR symbol_value = bfd_getb32 (bufp->symbol_value);
      asection *section = NULL;

      QUIT;

      /* Compute the section.  */
      switch (symbol_scope)
	{
	case SS_EXTERNAL:
	  if (symbol_type != ST_STORAGE)
	    section = bfd_und_section_ptr;
	  else
	    section = bfd_com_section_ptr;
	  break;

	case SS_UNSAT:
	  if (symbol_type != ST_STORAGE)
	    section = bfd_und_section_ptr;
	  else
	    section = bfd_com_section_ptr;
	  break;

	case SS_UNIVERSAL:
	  section = bfd_section_from_som_symbol (abfd, bufp);
	  break;

	case SS_LOCAL:
	  section = bfd_section_from_som_symbol (abfd, bufp);
	  break;
	}

      switch (symbol_scope)
	{
	case SS_UNIVERSAL:
	case SS_EXTERNAL:
	  switch (symbol_type)
	    {
	    case ST_SYM_EXT:
	    case ST_ARG_EXT:
	      continue;

	    case ST_CODE:
	    case ST_PRI_PROG:
	    case ST_SEC_PROG:
	    case ST_MILLICODE:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      ms_type = mst_text;
	      symbol_value += text_offset;
	      symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
	      break;

	    case ST_ENTRY:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      /* For a dynamic executable, ST_ENTRY symbols are
	         the stubs, while the ST_CODE symbol is the real
	         function.  */
	      if (dynamic)
		ms_type = mst_solib_trampoline;
	      else
		ms_type = mst_text;
	      symbol_value += text_offset;
	      symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
	      break;

	    case ST_STUB:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      ms_type = mst_solib_trampoline;
	      symbol_value += text_offset;
	      symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
	      break;

	    case ST_DATA:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      symbol_value += data_offset;
	      ms_type = mst_data;
	      break;
	    default:
	      continue;
	    }
	  break;

#if 0
	  /* SS_GLOBAL and SS_LOCAL are two names for the same thing (!).  */
	case SS_GLOBAL:
#endif
	case SS_LOCAL:
	  switch (symbol_type)
	    {
	    case ST_SYM_EXT:
	    case ST_ARG_EXT:
	      continue;

	    case ST_CODE:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      ms_type = mst_file_text;
	      symbol_value += text_offset;
	      symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);

	    check_strange_names:
	      /* Utah GCC 2.5, FSF GCC 2.6 and later generate correct local
	         label prefixes for stabs, constant data, etc.  So we need
	         only filter out L$ symbols which are left in due to
	         limitations in how GAS generates SOM relocations.

	         When linking in the HPUX C-library the HP linker has
	         the nasty habit of placing section symbols from the literal
	         subspaces in the middle of the program's text.  Filter
	         those out as best we can.  Check for first and last character
	         being '$'.

	         And finally, the newer HP compilers emit crud like $PIC_foo$N
	         in some circumstance (PIC code I guess).  It's also claimed
	         that they emit D$ symbols too.  What stupidity.  */
	      if ((symname[0] == 'L' && symname[1] == '$')
	      || (symname[0] == '$' && symname[strlen (symname) - 1] == '$')
		  || (symname[0] == 'D' && symname[1] == '$')
		  || (strncmp (symname, "L0\001", 3) == 0)
		  || (strncmp (symname, "$PIC", 4) == 0))
		continue;
	      break;

	    case ST_PRI_PROG:
	    case ST_SEC_PROG:
	    case ST_MILLICODE:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      ms_type = mst_file_text;
	      symbol_value += text_offset;
	      symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
	      break;

	    case ST_ENTRY:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      /* SS_LOCAL symbols in a shared library do not have
		 export stubs, so we do not have to worry about
		 using mst_file_text vs mst_solib_trampoline here like
		 we do for SS_UNIVERSAL and SS_EXTERNAL symbols above.  */
	      ms_type = mst_file_text;
	      symbol_value += text_offset;
	      symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
	      break;

	    case ST_STUB:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      ms_type = mst_solib_trampoline;
	      symbol_value += text_offset;
	      symbol_value = gdbarch_addr_bits_remove (gdbarch, symbol_value);
	      break;


	    case ST_DATA:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      symbol_value += data_offset;
	      ms_type = mst_file_data;
	      goto check_strange_names;

	    default:
	      continue;
	    }
	  break;

	  /* This can happen for common symbols when -E is passed to the
	     final link.  No idea _why_ that would make the linker force
	     common symbols to have an SS_UNSAT scope, but it does.

	     This also happens for weak symbols, but their type is
	     ST_DATA.  */
	case SS_UNSAT:
	  switch (symbol_type)
	    {
	    case ST_STORAGE:
	    case ST_DATA:
	      symname = bfd_getb32 (bufp->name) + stringtab;
	      symbol_value += data_offset;
	      ms_type = mst_data;
	      break;

	    default:
	      continue;
	    }
	  break;

	default:
	  continue;
	}

      if (bfd_getb32 (bufp->name) > obj_som_stringtab_size (abfd))
	error (_("Invalid symbol data; bad HP string table offset: %s"),
	       plongest (bfd_getb32 (bufp->name)));

      if (bfd_is_const_section (section))
	{
	  struct obj_section *iter;

	  ALL_OBJFILE_OSECTIONS (objfile, iter)
	    {
	      if (bfd_is_const_section (iter->the_bfd_section))
		continue;

	      if (obj_section_addr (iter) <= symbol_value
		  && symbol_value < obj_section_endaddr (iter))
		{
		  section = iter->the_bfd_section;
		  break;
		}
	    }
	}

      prim_record_minimal_symbol_and_info (symname, symbol_value, ms_type,
					   gdb_bfd_section_index (objfile->obfd,
								  section),
					   objfile);
    }

  do_cleanups (cleanup);
}
Пример #11
0
static void
store_register (const struct regcache *regcache, int regno)
{
  struct gdbarch *gdbarch = get_regcache_arch (regcache);
  struct reg inferior_registers;
  int ret;

  ret = ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid),
		(PTRACE_TYPE_ARG3) &inferior_registers, 0);

  if (ret < 0)
    {
      warning (_("unable to fetch general registers"));
      return;
    }

  switch (regno)
    {
    case ARM_SP_REGNUM:
      regcache_raw_collect (regcache, ARM_SP_REGNUM,
			    (char *) &inferior_registers.r_sp);
      break;

    case ARM_LR_REGNUM:
      regcache_raw_collect (regcache, ARM_LR_REGNUM,
			    (char *) &inferior_registers.r_lr);
      break;

    case ARM_PC_REGNUM:
      if (arm_apcs_32)
	regcache_raw_collect (regcache, ARM_PC_REGNUM,
			      (char *) &inferior_registers.r_pc);
      else
	{
	  unsigned pc_val;

	  regcache_raw_collect (regcache, ARM_PC_REGNUM,
				(char *) &pc_val);
	  
	  pc_val = gdbarch_addr_bits_remove (gdbarch, pc_val);
	  inferior_registers.r_pc ^= gdbarch_addr_bits_remove
				       (gdbarch, inferior_registers.r_pc);
	  inferior_registers.r_pc |= pc_val;
	}
      break;

    case ARM_PS_REGNUM:
      if (arm_apcs_32)
	regcache_raw_collect (regcache, ARM_PS_REGNUM,
			      (char *) &inferior_registers.r_cpsr);
      else
	{
	  unsigned psr_val;

	  regcache_raw_collect (regcache, ARM_PS_REGNUM,
				(char *) &psr_val);

	  psr_val ^= gdbarch_addr_bits_remove (gdbarch, psr_val);
	  inferior_registers.r_pc = gdbarch_addr_bits_remove
				      (gdbarch, inferior_registers.r_pc);
	  inferior_registers.r_pc |= psr_val;
	}
      break;

    default:
      regcache_raw_collect (regcache, regno,
			    (char *) &inferior_registers.r[regno]);
      break;
    }

  ret = ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid),
		(PTRACE_TYPE_ARG3) &inferior_registers, 0);

  if (ret < 0)
    warning (_("unable to write register %d to inferior"), regno);
}