OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gdb-7.1/] [gdb/] [gdbserver/] [linux-arm-low.c] - Diff between revs 227 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 227 Rev 816
/* GNU/Linux/ARM specific low level interface, for the remote server for GDB.
/* GNU/Linux/ARM specific low level interface, for the remote server for GDB.
   Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
   Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
   2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#include "server.h"
#include "server.h"
#include "linux-low.h"
#include "linux-low.h"
 
 
/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h.
/* Don't include elf.h if linux/elf.h got included by gdb_proc_service.h.
   On Bionic elf.h and linux/elf.h have conflicting definitions.  */
   On Bionic elf.h and linux/elf.h have conflicting definitions.  */
#ifndef ELFMAG0
#ifndef ELFMAG0
#include <elf.h>
#include <elf.h>
#endif
#endif
#include <sys/ptrace.h>
#include <sys/ptrace.h>
 
 
/* Defined in auto-generated files.  */
/* Defined in auto-generated files.  */
void init_registers_arm (void);
void init_registers_arm (void);
void init_registers_arm_with_iwmmxt (void);
void init_registers_arm_with_iwmmxt (void);
void init_registers_arm_with_vfpv2 (void);
void init_registers_arm_with_vfpv2 (void);
void init_registers_arm_with_vfpv3 (void);
void init_registers_arm_with_vfpv3 (void);
void init_registers_arm_with_neon (void);
void init_registers_arm_with_neon (void);
 
 
#ifndef PTRACE_GET_THREAD_AREA
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 22
#define PTRACE_GET_THREAD_AREA 22
#endif
#endif
 
 
#ifndef PTRACE_GETWMMXREGS
#ifndef PTRACE_GETWMMXREGS
# define PTRACE_GETWMMXREGS 18
# define PTRACE_GETWMMXREGS 18
# define PTRACE_SETWMMXREGS 19
# define PTRACE_SETWMMXREGS 19
#endif
#endif
 
 
#ifndef PTRACE_GETVFPREGS
#ifndef PTRACE_GETVFPREGS
# define PTRACE_GETVFPREGS 27
# define PTRACE_GETVFPREGS 27
# define PTRACE_SETVFPREGS 28
# define PTRACE_SETVFPREGS 28
#endif
#endif
 
 
static unsigned long arm_hwcap;
static unsigned long arm_hwcap;
 
 
/* These are in <asm/elf.h> in current kernels.  */
/* These are in <asm/elf.h> in current kernels.  */
#define HWCAP_VFP       64
#define HWCAP_VFP       64
#define HWCAP_IWMMXT    512
#define HWCAP_IWMMXT    512
#define HWCAP_NEON      4096
#define HWCAP_NEON      4096
#define HWCAP_VFPv3     8192
#define HWCAP_VFPv3     8192
#define HWCAP_VFPv3D16  16384
#define HWCAP_VFPv3D16  16384
 
 
#ifdef HAVE_SYS_REG_H
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
#include <sys/reg.h>
#endif
#endif
 
 
#define arm_num_regs 26
#define arm_num_regs 26
 
 
static int arm_regmap[] = {
static int arm_regmap[] = {
  0, 4, 8, 12, 16, 20, 24, 28,
  0, 4, 8, 12, 16, 20, 24, 28,
  32, 36, 40, 44, 48, 52, 56, 60,
  32, 36, 40, 44, 48, 52, 56, 60,
  -1, -1, -1, -1, -1, -1, -1, -1, -1,
  -1, -1, -1, -1, -1, -1, -1, -1, -1,
  64
  64
};
};
 
 
static int
static int
arm_cannot_store_register (int regno)
arm_cannot_store_register (int regno)
{
{
  return (regno >= arm_num_regs);
  return (regno >= arm_num_regs);
}
}
 
 
static int
static int
arm_cannot_fetch_register (int regno)
arm_cannot_fetch_register (int regno)
{
{
  return (regno >= arm_num_regs);
  return (regno >= arm_num_regs);
}
}
 
 
static void
static void
arm_fill_gregset (struct regcache *regcache, void *buf)
arm_fill_gregset (struct regcache *regcache, void *buf)
{
{
  int i;
  int i;
 
 
  for (i = 0; i < arm_num_regs; i++)
  for (i = 0; i < arm_num_regs; i++)
    if (arm_regmap[i] != -1)
    if (arm_regmap[i] != -1)
      collect_register (regcache, i, ((char *) buf) + arm_regmap[i]);
      collect_register (regcache, i, ((char *) buf) + arm_regmap[i]);
}
}
 
 
static void
static void
arm_store_gregset (struct regcache *regcache, const void *buf)
arm_store_gregset (struct regcache *regcache, const void *buf)
{
{
  int i;
  int i;
  char zerobuf[8];
  char zerobuf[8];
 
 
  memset (zerobuf, 0, 8);
  memset (zerobuf, 0, 8);
  for (i = 0; i < arm_num_regs; i++)
  for (i = 0; i < arm_num_regs; i++)
    if (arm_regmap[i] != -1)
    if (arm_regmap[i] != -1)
      supply_register (regcache, i, ((char *) buf) + arm_regmap[i]);
      supply_register (regcache, i, ((char *) buf) + arm_regmap[i]);
    else
    else
      supply_register (regcache, i, zerobuf);
      supply_register (regcache, i, zerobuf);
}
}
 
 
static void
static void
arm_fill_wmmxregset (struct regcache *regcache, void *buf)
arm_fill_wmmxregset (struct regcache *regcache, void *buf)
{
{
  int i;
  int i;
 
 
  if (!(arm_hwcap & HWCAP_IWMMXT))
  if (!(arm_hwcap & HWCAP_IWMMXT))
    return;
    return;
 
 
  for (i = 0; i < 16; i++)
  for (i = 0; i < 16; i++)
    collect_register (regcache, arm_num_regs + i, (char *) buf + i * 8);
    collect_register (regcache, arm_num_regs + i, (char *) buf + i * 8);
 
 
  /* We only have access to wcssf, wcasf, and wcgr0-wcgr3.  */
  /* We only have access to wcssf, wcasf, and wcgr0-wcgr3.  */
  for (i = 0; i < 6; i++)
  for (i = 0; i < 6; i++)
    collect_register (regcache, arm_num_regs + i + 16,
    collect_register (regcache, arm_num_regs + i + 16,
                      (char *) buf + 16 * 8 + i * 4);
                      (char *) buf + 16 * 8 + i * 4);
}
}
 
 
static void
static void
arm_store_wmmxregset (struct regcache *regcache, const void *buf)
arm_store_wmmxregset (struct regcache *regcache, const void *buf)
{
{
  int i;
  int i;
 
 
  if (!(arm_hwcap & HWCAP_IWMMXT))
  if (!(arm_hwcap & HWCAP_IWMMXT))
    return;
    return;
 
 
  for (i = 0; i < 16; i++)
  for (i = 0; i < 16; i++)
    supply_register (regcache, arm_num_regs + i, (char *) buf + i * 8);
    supply_register (regcache, arm_num_regs + i, (char *) buf + i * 8);
 
 
  /* We only have access to wcssf, wcasf, and wcgr0-wcgr3.  */
  /* We only have access to wcssf, wcasf, and wcgr0-wcgr3.  */
  for (i = 0; i < 6; i++)
  for (i = 0; i < 6; i++)
    supply_register (regcache, arm_num_regs + i + 16,
    supply_register (regcache, arm_num_regs + i + 16,
                     (char *) buf + 16 * 8 + i * 4);
                     (char *) buf + 16 * 8 + i * 4);
}
}
 
 
static void
static void
arm_fill_vfpregset (struct regcache *regcache, void *buf)
arm_fill_vfpregset (struct regcache *regcache, void *buf)
{
{
  int i, num, base;
  int i, num, base;
 
 
  if (!(arm_hwcap & HWCAP_VFP))
  if (!(arm_hwcap & HWCAP_VFP))
    return;
    return;
 
 
  if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
  if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
    num = 32;
    num = 32;
  else
  else
    num = 16;
    num = 16;
 
 
  base = find_regno ("d0");
  base = find_regno ("d0");
  for (i = 0; i < num; i++)
  for (i = 0; i < num; i++)
    collect_register (regcache, base + i, (char *) buf + i * 8);
    collect_register (regcache, base + i, (char *) buf + i * 8);
 
 
  collect_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
  collect_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
}
}
 
 
static void
static void
arm_store_vfpregset (struct regcache *regcache, const void *buf)
arm_store_vfpregset (struct regcache *regcache, const void *buf)
{
{
  int i, num, base;
  int i, num, base;
 
 
  if (!(arm_hwcap & HWCAP_VFP))
  if (!(arm_hwcap & HWCAP_VFP))
    return;
    return;
 
 
  if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
  if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
    num = 32;
    num = 32;
  else
  else
    num = 16;
    num = 16;
 
 
  base = find_regno ("d0");
  base = find_regno ("d0");
  for (i = 0; i < num; i++)
  for (i = 0; i < num; i++)
    supply_register (regcache, base + i, (char *) buf + i * 8);
    supply_register (regcache, base + i, (char *) buf + i * 8);
 
 
  supply_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
  supply_register_by_name (regcache, "fpscr", (char *) buf + 32 * 8);
}
}
 
 
extern int debug_threads;
extern int debug_threads;
 
 
static CORE_ADDR
static CORE_ADDR
arm_get_pc (struct regcache *regcache)
arm_get_pc (struct regcache *regcache)
{
{
  unsigned long pc;
  unsigned long pc;
  collect_register_by_name (regcache, "pc", &pc);
  collect_register_by_name (regcache, "pc", &pc);
  if (debug_threads)
  if (debug_threads)
    fprintf (stderr, "stop pc is %08lx\n", pc);
    fprintf (stderr, "stop pc is %08lx\n", pc);
  return pc;
  return pc;
}
}
 
 
static void
static void
arm_set_pc (struct regcache *regcache, CORE_ADDR pc)
arm_set_pc (struct regcache *regcache, CORE_ADDR pc)
{
{
  unsigned long newpc = pc;
  unsigned long newpc = pc;
  supply_register_by_name (regcache, "pc", &newpc);
  supply_register_by_name (regcache, "pc", &newpc);
}
}
 
 
/* Correct in either endianness.  */
/* Correct in either endianness.  */
static const unsigned long arm_breakpoint = 0xef9f0001;
static const unsigned long arm_breakpoint = 0xef9f0001;
#define arm_breakpoint_len 4
#define arm_breakpoint_len 4
static const unsigned short thumb_breakpoint = 0xde01;
static const unsigned short thumb_breakpoint = 0xde01;
static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 };
static const unsigned short thumb2_breakpoint[] = { 0xf7f0, 0xa000 };
 
 
/* For new EABI binaries.  We recognize it regardless of which ABI
/* For new EABI binaries.  We recognize it regardless of which ABI
   is used for gdbserver, so single threaded debugging should work
   is used for gdbserver, so single threaded debugging should work
   OK, but for multi-threaded debugging we only insert the current
   OK, but for multi-threaded debugging we only insert the current
   ABI's breakpoint instruction.  For now at least.  */
   ABI's breakpoint instruction.  For now at least.  */
static const unsigned long arm_eabi_breakpoint = 0xe7f001f0;
static const unsigned long arm_eabi_breakpoint = 0xe7f001f0;
 
 
static int
static int
arm_breakpoint_at (CORE_ADDR where)
arm_breakpoint_at (CORE_ADDR where)
{
{
  struct regcache *regcache = get_thread_regcache (current_inferior, 1);
  struct regcache *regcache = get_thread_regcache (current_inferior, 1);
  unsigned long cpsr;
  unsigned long cpsr;
 
 
  collect_register_by_name (regcache, "cpsr", &cpsr);
  collect_register_by_name (regcache, "cpsr", &cpsr);
 
 
  if (cpsr & 0x20)
  if (cpsr & 0x20)
    {
    {
      /* Thumb mode.  */
      /* Thumb mode.  */
      unsigned short insn;
      unsigned short insn;
 
 
      (*the_target->read_memory) (where, (unsigned char *) &insn, 2);
      (*the_target->read_memory) (where, (unsigned char *) &insn, 2);
      if (insn == thumb_breakpoint)
      if (insn == thumb_breakpoint)
        return 1;
        return 1;
 
 
      if (insn == thumb2_breakpoint[0])
      if (insn == thumb2_breakpoint[0])
        {
        {
          (*the_target->read_memory) (where + 2, (unsigned char *) &insn, 2);
          (*the_target->read_memory) (where + 2, (unsigned char *) &insn, 2);
          if (insn == thumb2_breakpoint[1])
          if (insn == thumb2_breakpoint[1])
            return 1;
            return 1;
        }
        }
    }
    }
  else
  else
    {
    {
      /* ARM mode.  */
      /* ARM mode.  */
      unsigned long insn;
      unsigned long insn;
 
 
      (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
      (*the_target->read_memory) (where, (unsigned char *) &insn, 4);
      if (insn == arm_breakpoint)
      if (insn == arm_breakpoint)
        return 1;
        return 1;
 
 
      if (insn == arm_eabi_breakpoint)
      if (insn == arm_eabi_breakpoint)
        return 1;
        return 1;
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 
/* We only place breakpoints in empty marker functions, and thread locking
/* We only place breakpoints in empty marker functions, and thread locking
   is outside of the function.  So rather than importing software single-step,
   is outside of the function.  So rather than importing software single-step,
   we can just run until exit.  */
   we can just run until exit.  */
static CORE_ADDR
static CORE_ADDR
arm_reinsert_addr (void)
arm_reinsert_addr (void)
{
{
  struct regcache *regcache = get_thread_regcache (current_inferior, 1);
  struct regcache *regcache = get_thread_regcache (current_inferior, 1);
  unsigned long pc;
  unsigned long pc;
  collect_register_by_name (regcache, "lr", &pc);
  collect_register_by_name (regcache, "lr", &pc);
  return pc;
  return pc;
}
}
 
 
/* Fetch the thread-local storage pointer for libthread_db.  */
/* Fetch the thread-local storage pointer for libthread_db.  */
 
 
ps_err_e
ps_err_e
ps_get_thread_area (const struct ps_prochandle *ph,
ps_get_thread_area (const struct ps_prochandle *ph,
                    lwpid_t lwpid, int idx, void **base)
                    lwpid_t lwpid, int idx, void **base)
{
{
  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
  if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
    return PS_ERR;
    return PS_ERR;
 
 
  /* IDX is the bias from the thread pointer to the beginning of the
  /* IDX is the bias from the thread pointer to the beginning of the
     thread descriptor.  It has to be subtracted due to implementation
     thread descriptor.  It has to be subtracted due to implementation
     quirks in libthread_db.  */
     quirks in libthread_db.  */
  *base = (void *) ((char *)*base - idx);
  *base = (void *) ((char *)*base - idx);
 
 
  return PS_OK;
  return PS_OK;
}
}
 
 
static int
static int
arm_get_hwcap (unsigned long *valp)
arm_get_hwcap (unsigned long *valp)
{
{
  unsigned char *data = alloca (8);
  unsigned char *data = alloca (8);
  int offset = 0;
  int offset = 0;
 
 
  while ((*the_target->read_auxv) (offset, data, 8) == 8)
  while ((*the_target->read_auxv) (offset, data, 8) == 8)
    {
    {
      unsigned int *data_p = (unsigned int *)data;
      unsigned int *data_p = (unsigned int *)data;
      if (data_p[0] == AT_HWCAP)
      if (data_p[0] == AT_HWCAP)
        {
        {
          *valp = data_p[1];
          *valp = data_p[1];
          return 1;
          return 1;
        }
        }
 
 
      offset += 8;
      offset += 8;
    }
    }
 
 
  *valp = 0;
  *valp = 0;
  return 0;
  return 0;
}
}
 
 
static void
static void
arm_arch_setup (void)
arm_arch_setup (void)
{
{
  arm_hwcap = 0;
  arm_hwcap = 0;
  if (arm_get_hwcap (&arm_hwcap) == 0)
  if (arm_get_hwcap (&arm_hwcap) == 0)
    {
    {
      init_registers_arm ();
      init_registers_arm ();
      return;
      return;
    }
    }
 
 
  if (arm_hwcap & HWCAP_IWMMXT)
  if (arm_hwcap & HWCAP_IWMMXT)
    {
    {
      init_registers_arm_with_iwmmxt ();
      init_registers_arm_with_iwmmxt ();
      return;
      return;
    }
    }
 
 
  if (arm_hwcap & HWCAP_VFP)
  if (arm_hwcap & HWCAP_VFP)
    {
    {
      int pid;
      int pid;
      char *buf;
      char *buf;
 
 
      /* NEON implies either no VFP, or VFPv3-D32.  We only support
      /* NEON implies either no VFP, or VFPv3-D32.  We only support
         it with VFP.  */
         it with VFP.  */
      if (arm_hwcap & HWCAP_NEON)
      if (arm_hwcap & HWCAP_NEON)
        init_registers_arm_with_neon ();
        init_registers_arm_with_neon ();
      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
      else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
        init_registers_arm_with_vfpv3 ();
        init_registers_arm_with_vfpv3 ();
      else
      else
        init_registers_arm_with_vfpv2 ();
        init_registers_arm_with_vfpv2 ();
 
 
      /* Now make sure that the kernel supports reading these
      /* Now make sure that the kernel supports reading these
         registers.  Support was added in 2.6.30.  */
         registers.  Support was added in 2.6.30.  */
      pid = lwpid_of (get_thread_lwp (current_inferior));
      pid = lwpid_of (get_thread_lwp (current_inferior));
      errno = 0;
      errno = 0;
      buf = malloc (32 * 8 + 4);
      buf = malloc (32 * 8 + 4);
      if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
      if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
          && errno == EIO)
          && errno == EIO)
        {
        {
          arm_hwcap = 0;
          arm_hwcap = 0;
          init_registers_arm ();
          init_registers_arm ();
        }
        }
      free (buf);
      free (buf);
 
 
      return;
      return;
    }
    }
 
 
  /* The default configuration uses legacy FPA registers, probably
  /* The default configuration uses legacy FPA registers, probably
     simulated.  */
     simulated.  */
  init_registers_arm ();
  init_registers_arm ();
}
}
 
 
struct regset_info target_regsets[] = {
struct regset_info target_regsets[] = {
  { PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4,
  { PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4,
    GENERAL_REGS,
    GENERAL_REGS,
    arm_fill_gregset, arm_store_gregset },
    arm_fill_gregset, arm_store_gregset },
  { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
  { PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
    EXTENDED_REGS,
    EXTENDED_REGS,
    arm_fill_wmmxregset, arm_store_wmmxregset },
    arm_fill_wmmxregset, arm_store_wmmxregset },
  { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 32 * 8 + 4,
  { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 32 * 8 + 4,
    EXTENDED_REGS,
    EXTENDED_REGS,
    arm_fill_vfpregset, arm_store_vfpregset },
    arm_fill_vfpregset, arm_store_vfpregset },
  { 0, 0, -1, -1, NULL, NULL }
  { 0, 0, -1, -1, NULL, NULL }
};
};
 
 
struct linux_target_ops the_low_target = {
struct linux_target_ops the_low_target = {
  arm_arch_setup,
  arm_arch_setup,
  arm_num_regs,
  arm_num_regs,
  arm_regmap,
  arm_regmap,
  arm_cannot_fetch_register,
  arm_cannot_fetch_register,
  arm_cannot_store_register,
  arm_cannot_store_register,
  arm_get_pc,
  arm_get_pc,
  arm_set_pc,
  arm_set_pc,
 
 
  /* Define an ARM-mode breakpoint; we only set breakpoints in the C
  /* Define an ARM-mode breakpoint; we only set breakpoints in the C
     library, which is most likely to be ARM.  If the kernel supports
     library, which is most likely to be ARM.  If the kernel supports
     clone events, we will never insert a breakpoint, so even a Thumb
     clone events, we will never insert a breakpoint, so even a Thumb
     C library will work; so will mixing EABI/non-EABI gdbserver and
     C library will work; so will mixing EABI/non-EABI gdbserver and
     application.  */
     application.  */
#ifndef __ARM_EABI__
#ifndef __ARM_EABI__
  (const unsigned char *) &arm_breakpoint,
  (const unsigned char *) &arm_breakpoint,
#else
#else
  (const unsigned char *) &arm_eabi_breakpoint,
  (const unsigned char *) &arm_eabi_breakpoint,
#endif
#endif
  arm_breakpoint_len,
  arm_breakpoint_len,
  arm_reinsert_addr,
  arm_reinsert_addr,
  0,
  0,
  arm_breakpoint_at,
  arm_breakpoint_at,
};
};
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.