OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [tags/] [gnu-src/] [gdb-6.8/] [pre-binutils-2.20.1-sync/] [gdb/] [gdbserver/] [linux-crisv32-low.c] - Diff between revs 157 and 223

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

Rev 157 Rev 223
/* GNU/Linux/CRIS specific low level interface, for the remote server for GDB.
/* GNU/Linux/CRIS 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,
   2007, 2008 Free Software Foundation, Inc.
   2007, 2008 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"
#include <sys/ptrace.h>
#include <sys/ptrace.h>
 
 
/* CRISv32 */
/* CRISv32 */
#define cris_num_regs 49
#define cris_num_regs 49
 
 
/* Note: Ignoring USP (having the stack pointer in two locations causes trouble
/* Note: Ignoring USP (having the stack pointer in two locations causes trouble
   without any significant gain).  */
   without any significant gain).  */
 
 
/* Locations need to match <include/asm/arch/ptrace.h>.  */
/* Locations need to match <include/asm/arch/ptrace.h>.  */
static int cris_regmap[] = {
static int cris_regmap[] = {
  1*4, 2*4, 3*4, 4*4,
  1*4, 2*4, 3*4, 4*4,
  5*4, 6*4, 7*4, 8*4,
  5*4, 6*4, 7*4, 8*4,
  9*4, 10*4, 11*4, 12*4,
  9*4, 10*4, 11*4, 12*4,
  13*4, 14*4, 24*4, 15*4,
  13*4, 14*4, 24*4, 15*4,
 
 
  -1, -1, -1, 16*4,
  -1, -1, -1, 16*4,
  -1, 22*4, 23*4, 17*4,
  -1, 22*4, 23*4, 17*4,
  -1, -1, 21*4, 20*4,
  -1, -1, 21*4, 20*4,
  -1, 19*4, -1, 18*4,
  -1, 19*4, -1, 18*4,
 
 
  25*4,
  25*4,
 
 
  26*4, -1,   -1,   29*4,
  26*4, -1,   -1,   29*4,
  30*4, 31*4, 32*4, 33*4,
  30*4, 31*4, 32*4, 33*4,
  34*4, 35*4, 36*4, 37*4,
  34*4, 35*4, 36*4, 37*4,
  38*4, 39*4, 40*4, -1
  38*4, 39*4, 40*4, -1
 
 
};
};
 
 
extern int debug_threads;
extern int debug_threads;
 
 
static CORE_ADDR
static CORE_ADDR
cris_get_pc (void)
cris_get_pc (void)
{
{
  unsigned long pc;
  unsigned long pc;
  collect_register_by_name ("pc", &pc);
  collect_register_by_name ("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
cris_set_pc (CORE_ADDR pc)
cris_set_pc (CORE_ADDR pc)
{
{
  unsigned long newpc = pc;
  unsigned long newpc = pc;
  supply_register_by_name ("pc", &newpc);
  supply_register_by_name ("pc", &newpc);
}
}
 
 
static const unsigned short cris_breakpoint = 0xe938;
static const unsigned short cris_breakpoint = 0xe938;
#define cris_breakpoint_len 2
#define cris_breakpoint_len 2
 
 
static int
static int
cris_breakpoint_at (CORE_ADDR where)
cris_breakpoint_at (CORE_ADDR where)
{
{
  unsigned short insn;
  unsigned short insn;
 
 
  (*the_target->read_memory) (where, (unsigned char *) &insn,
  (*the_target->read_memory) (where, (unsigned char *) &insn,
                              cris_breakpoint_len);
                              cris_breakpoint_len);
  if (insn == cris_breakpoint)
  if (insn == cris_breakpoint)
    return 1;
    return 1;
 
 
  /* If necessary, recognize more trap instructions here.  GDB only uses the
  /* If necessary, recognize more trap instructions here.  GDB only uses the
     one.  */
     one.  */
  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.  */
 
 
/* FIXME: This function should not be needed, since we have PTRACE_SINGLESTEP
/* FIXME: This function should not be needed, since we have PTRACE_SINGLESTEP
   for CRISv32.  Without it, td_ta_event_getmsg in thread_db_create_event
   for CRISv32.  Without it, td_ta_event_getmsg in thread_db_create_event
   will fail when debugging multi-threaded applications.  */
   will fail when debugging multi-threaded applications.  */
 
 
static CORE_ADDR
static CORE_ADDR
cris_reinsert_addr (void)
cris_reinsert_addr (void)
{
{
  unsigned long pc;
  unsigned long pc;
  collect_register_by_name ("srp", &pc);
  collect_register_by_name ("srp", &pc);
  return pc;
  return pc;
}
}
 
 
static void
static void
cris_write_data_breakpoint (int bp, unsigned long start, unsigned long end)
cris_write_data_breakpoint (int bp, unsigned long start, unsigned long end)
{
{
  switch (bp)
  switch (bp)
    {
    {
    case 0:
    case 0:
      supply_register_by_name ("s3", &start);
      supply_register_by_name ("s3", &start);
      supply_register_by_name ("s4", &end);
      supply_register_by_name ("s4", &end);
      break;
      break;
    case 1:
    case 1:
      supply_register_by_name ("s5", &start);
      supply_register_by_name ("s5", &start);
      supply_register_by_name ("s6", &end);
      supply_register_by_name ("s6", &end);
      break;
      break;
    case 2:
    case 2:
      supply_register_by_name ("s7", &start);
      supply_register_by_name ("s7", &start);
      supply_register_by_name ("s8", &end);
      supply_register_by_name ("s8", &end);
      break;
      break;
    case 3:
    case 3:
      supply_register_by_name ("s9", &start);
      supply_register_by_name ("s9", &start);
      supply_register_by_name ("s10", &end);
      supply_register_by_name ("s10", &end);
      break;
      break;
    case 4:
    case 4:
      supply_register_by_name ("s11", &start);
      supply_register_by_name ("s11", &start);
      supply_register_by_name ("s12", &end);
      supply_register_by_name ("s12", &end);
      break;
      break;
    case 5:
    case 5:
      supply_register_by_name ("s13", &start);
      supply_register_by_name ("s13", &start);
      supply_register_by_name ("s14", &end);
      supply_register_by_name ("s14", &end);
      break;
      break;
    }
    }
}
}
 
 
static int
static int
cris_insert_watchpoint (char type, CORE_ADDR addr, int len)
cris_insert_watchpoint (char type, CORE_ADDR addr, int len)
{
{
  int bp;
  int bp;
  unsigned long bp_ctrl;
  unsigned long bp_ctrl;
  unsigned long start, end;
  unsigned long start, end;
  unsigned long ccs;
  unsigned long ccs;
 
 
  /* Breakpoint/watchpoint types (GDB terminology):
  /* Breakpoint/watchpoint types (GDB terminology):
     0 = memory breakpoint for instructions
     0 = memory breakpoint for instructions
     (not supported; done via memory write instead)
     (not supported; done via memory write instead)
     1 = hardware breakpoint for instructions (not supported)
     1 = hardware breakpoint for instructions (not supported)
     2 = write watchpoint (supported)
     2 = write watchpoint (supported)
     3 = read watchpoint (supported)
     3 = read watchpoint (supported)
     4 = access watchpoint (supported).  */
     4 = access watchpoint (supported).  */
 
 
  if (type < '2' || type > '4')
  if (type < '2' || type > '4')
    {
    {
      /* Unsupported.  */
      /* Unsupported.  */
      return 1;
      return 1;
    }
    }
 
 
  /* Read watchpoints are set as access watchpoints, because of GDB's
  /* Read watchpoints are set as access watchpoints, because of GDB's
     inability to deal with pure read watchpoints.  */
     inability to deal with pure read watchpoints.  */
  if (type == '3')
  if (type == '3')
    type = '4';
    type = '4';
 
 
  /* Get the configuration register.  */
  /* Get the configuration register.  */
  collect_register_by_name ("s0", &bp_ctrl);
  collect_register_by_name ("s0", &bp_ctrl);
 
 
  /* The watchpoint allocation scheme is the simplest possible.
  /* The watchpoint allocation scheme is the simplest possible.
     For example, if a region is watched for read and
     For example, if a region is watched for read and
     a write watch is requested, a new watchpoint will
     a write watch is requested, a new watchpoint will
     be used.  Also, if a watch for a region that is already
     be used.  Also, if a watch for a region that is already
     covered by one or more existing watchpoints, a new
     covered by one or more existing watchpoints, a new
     watchpoint will be used.  */
     watchpoint will be used.  */
 
 
  /* First, find a free data watchpoint.  */
  /* First, find a free data watchpoint.  */
  for (bp = 0; bp < 6; bp++)
  for (bp = 0; bp < 6; bp++)
    {
    {
      /* Each data watchpoint's control registers occupy 2 bits
      /* Each data watchpoint's control registers occupy 2 bits
         (hence the 3), starting at bit 2 for D0 (hence the 2)
         (hence the 3), starting at bit 2 for D0 (hence the 2)
         with 4 bits between for each watchpoint (yes, the 4).  */
         with 4 bits between for each watchpoint (yes, the 4).  */
      if (!(bp_ctrl & (0x3 << (2 + (bp * 4)))))
      if (!(bp_ctrl & (0x3 << (2 + (bp * 4)))))
        break;
        break;
    }
    }
 
 
  if (bp > 5)
  if (bp > 5)
    {
    {
      /* We're out of watchpoints.  */
      /* We're out of watchpoints.  */
      return -1;
      return -1;
    }
    }
 
 
  /* Configure the control register first.  */
  /* Configure the control register first.  */
  if (type == '3' || type == '4')
  if (type == '3' || type == '4')
    {
    {
      /* Trigger on read.  */
      /* Trigger on read.  */
      bp_ctrl |= (1 << (2 + bp * 4));
      bp_ctrl |= (1 << (2 + bp * 4));
    }
    }
  if (type == '2' || type == '4')
  if (type == '2' || type == '4')
    {
    {
      /* Trigger on write.  */
      /* Trigger on write.  */
      bp_ctrl |= (2 << (2 + bp * 4));
      bp_ctrl |= (2 << (2 + bp * 4));
    }
    }
 
 
  /* Setup the configuration register.  */
  /* Setup the configuration register.  */
  supply_register_by_name ("s0", &bp_ctrl);
  supply_register_by_name ("s0", &bp_ctrl);
 
 
  /* Setup the range.  */
  /* Setup the range.  */
  start = addr;
  start = addr;
  end = addr + len - 1;
  end = addr + len - 1;
 
 
  /* Configure the watchpoint register.  */
  /* Configure the watchpoint register.  */
  cris_write_data_breakpoint (bp, start, end);
  cris_write_data_breakpoint (bp, start, end);
 
 
  collect_register_by_name ("ccs", &ccs);
  collect_register_by_name ("ccs", &ccs);
  /* Set the S1 flag to enable watchpoints.  */
  /* Set the S1 flag to enable watchpoints.  */
  ccs |= (1 << 19);
  ccs |= (1 << 19);
  supply_register_by_name ("ccs", &ccs);
  supply_register_by_name ("ccs", &ccs);
 
 
  return 0;
  return 0;
}
}
 
 
static int
static int
cris_remove_watchpoint (char type, CORE_ADDR addr, int len)
cris_remove_watchpoint (char type, CORE_ADDR addr, int len)
{
{
  int bp;
  int bp;
  unsigned long bp_ctrl;
  unsigned long bp_ctrl;
  unsigned long start, end;
  unsigned long start, end;
 
 
  /* Breakpoint/watchpoint types:
  /* Breakpoint/watchpoint types:
     0 = memory breakpoint for instructions
     0 = memory breakpoint for instructions
     (not supported; done via memory write instead)
     (not supported; done via memory write instead)
     1 = hardware breakpoint for instructions (not supported)
     1 = hardware breakpoint for instructions (not supported)
     2 = write watchpoint (supported)
     2 = write watchpoint (supported)
     3 = read watchpoint (supported)
     3 = read watchpoint (supported)
     4 = access watchpoint (supported).  */
     4 = access watchpoint (supported).  */
  if (type < '2' || type > '4')
  if (type < '2' || type > '4')
    return -1;
    return -1;
 
 
  /* Read watchpoints are set as access watchpoints, because of GDB's
  /* Read watchpoints are set as access watchpoints, because of GDB's
     inability to deal with pure read watchpoints.  */
     inability to deal with pure read watchpoints.  */
  if (type == '3')
  if (type == '3')
    type = '4';
    type = '4';
 
 
  /* Get the configuration register.  */
  /* Get the configuration register.  */
  collect_register_by_name ("s0", &bp_ctrl);
  collect_register_by_name ("s0", &bp_ctrl);
 
 
  /* Try to find a watchpoint that is configured for the
  /* Try to find a watchpoint that is configured for the
     specified range, then check that read/write also matches.  */
     specified range, then check that read/write also matches.  */
 
 
  /* Ugly pointer arithmetic, since I cannot rely on a
  /* Ugly pointer arithmetic, since I cannot rely on a
     single switch (addr) as there may be several watchpoints with
     single switch (addr) as there may be several watchpoints with
     the same start address for example.  */
     the same start address for example.  */
 
 
  unsigned long bp_d_regs[12];
  unsigned long bp_d_regs[12];
 
 
  /* Get all range registers to simplify search.  */
  /* Get all range registers to simplify search.  */
  collect_register_by_name ("s3", &bp_d_regs[0]);
  collect_register_by_name ("s3", &bp_d_regs[0]);
  collect_register_by_name ("s4", &bp_d_regs[1]);
  collect_register_by_name ("s4", &bp_d_regs[1]);
  collect_register_by_name ("s5", &bp_d_regs[2]);
  collect_register_by_name ("s5", &bp_d_regs[2]);
  collect_register_by_name ("s6", &bp_d_regs[3]);
  collect_register_by_name ("s6", &bp_d_regs[3]);
  collect_register_by_name ("s7", &bp_d_regs[4]);
  collect_register_by_name ("s7", &bp_d_regs[4]);
  collect_register_by_name ("s8", &bp_d_regs[5]);
  collect_register_by_name ("s8", &bp_d_regs[5]);
  collect_register_by_name ("s9", &bp_d_regs[6]);
  collect_register_by_name ("s9", &bp_d_regs[6]);
  collect_register_by_name ("s10", &bp_d_regs[7]);
  collect_register_by_name ("s10", &bp_d_regs[7]);
  collect_register_by_name ("s11", &bp_d_regs[8]);
  collect_register_by_name ("s11", &bp_d_regs[8]);
  collect_register_by_name ("s12", &bp_d_regs[9]);
  collect_register_by_name ("s12", &bp_d_regs[9]);
  collect_register_by_name ("s13", &bp_d_regs[10]);
  collect_register_by_name ("s13", &bp_d_regs[10]);
  collect_register_by_name ("s14", &bp_d_regs[11]);
  collect_register_by_name ("s14", &bp_d_regs[11]);
 
 
  for (bp = 0; bp < 6; bp++)
  for (bp = 0; bp < 6; bp++)
    {
    {
      if (bp_d_regs[bp * 2] == addr
      if (bp_d_regs[bp * 2] == addr
          && bp_d_regs[bp * 2 + 1] == (addr + len - 1)) {
          && bp_d_regs[bp * 2 + 1] == (addr + len - 1)) {
        /* Matching range.  */
        /* Matching range.  */
        int bitpos = 2 + bp * 4;
        int bitpos = 2 + bp * 4;
        int rw_bits;
        int rw_bits;
 
 
        /* Read/write bits for this BP.  */
        /* Read/write bits for this BP.  */
        rw_bits = (bp_ctrl & (0x3 << bitpos)) >> bitpos;
        rw_bits = (bp_ctrl & (0x3 << bitpos)) >> bitpos;
 
 
        if ((type == '3' && rw_bits == 0x1)
        if ((type == '3' && rw_bits == 0x1)
            || (type == '2' && rw_bits == 0x2)
            || (type == '2' && rw_bits == 0x2)
            || (type == '4' && rw_bits == 0x3))
            || (type == '4' && rw_bits == 0x3))
          {
          {
            /* Read/write matched.  */
            /* Read/write matched.  */
            break;
            break;
          }
          }
      }
      }
    }
    }
 
 
  if (bp > 5)
  if (bp > 5)
    {
    {
      /* No watchpoint matched.  */
      /* No watchpoint matched.  */
      return -1;
      return -1;
    }
    }
 
 
  /* Found a matching watchpoint.  Now, deconfigure it by
  /* Found a matching watchpoint.  Now, deconfigure it by
     both disabling read/write in bp_ctrl and zeroing its
     both disabling read/write in bp_ctrl and zeroing its
     start/end addresses.  */
     start/end addresses.  */
  bp_ctrl &= ~(3 << (2 + (bp * 4)));
  bp_ctrl &= ~(3 << (2 + (bp * 4)));
  /* Setup the configuration register.  */
  /* Setup the configuration register.  */
  supply_register_by_name ("s0", &bp_ctrl);
  supply_register_by_name ("s0", &bp_ctrl);
 
 
  start = end = 0;
  start = end = 0;
  /* Configure the watchpoint register.  */
  /* Configure the watchpoint register.  */
  cris_write_data_breakpoint (bp, start, end);
  cris_write_data_breakpoint (bp, start, end);
 
 
  /* Note that we don't clear the S1 flag here.  It's done when continuing.  */
  /* Note that we don't clear the S1 flag here.  It's done when continuing.  */
  return 0;
  return 0;
}
}
 
 
static int
static int
cris_stopped_by_watchpoint (void)
cris_stopped_by_watchpoint (void)
{
{
  unsigned long exs;
  unsigned long exs;
 
 
  collect_register_by_name ("exs", &exs);
  collect_register_by_name ("exs", &exs);
 
 
  return (((exs & 0xff00) >> 8) == 0xc);
  return (((exs & 0xff00) >> 8) == 0xc);
}
}
 
 
static CORE_ADDR
static CORE_ADDR
cris_stopped_data_address (void)
cris_stopped_data_address (void)
{
{
  unsigned long eda;
  unsigned long eda;
 
 
  collect_register_by_name ("eda", &eda);
  collect_register_by_name ("eda", &eda);
 
 
  /* FIXME: Possibly adjust to match watched range.  */
  /* FIXME: Possibly adjust to match watched range.  */
  return eda;
  return eda;
}
}
 
 
static void
static void
cris_fill_gregset (void *buf)
cris_fill_gregset (void *buf)
{
{
  int i;
  int i;
 
 
  for (i = 0; i < cris_num_regs; i++)
  for (i = 0; i < cris_num_regs; i++)
    {
    {
      if (cris_regmap[i] != -1)
      if (cris_regmap[i] != -1)
        collect_register (i, ((char *) buf) + cris_regmap[i]);
        collect_register (i, ((char *) buf) + cris_regmap[i]);
    }
    }
}
}
 
 
static void
static void
cris_store_gregset (const void *buf)
cris_store_gregset (const void *buf)
{
{
  int i;
  int i;
 
 
  for (i = 0; i < cris_num_regs; i++)
  for (i = 0; i < cris_num_regs; i++)
    {
    {
      if (cris_regmap[i] != -1)
      if (cris_regmap[i] != -1)
        supply_register (i, ((char *) buf) + cris_regmap[i]);
        supply_register (i, ((char *) buf) + cris_regmap[i]);
    }
    }
}
}
 
 
typedef unsigned long elf_gregset_t[cris_num_regs];
typedef unsigned long elf_gregset_t[cris_num_regs];
 
 
struct regset_info target_regsets[] = {
struct regset_info target_regsets[] = {
  { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
  { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
    GENERAL_REGS, cris_fill_gregset, cris_store_gregset },
    GENERAL_REGS, cris_fill_gregset, cris_store_gregset },
  { 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 = {
  -1,
  -1,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  NULL,
  cris_get_pc,
  cris_get_pc,
  cris_set_pc,
  cris_set_pc,
  (const unsigned char *) &cris_breakpoint,
  (const unsigned char *) &cris_breakpoint,
  cris_breakpoint_len,
  cris_breakpoint_len,
  cris_reinsert_addr,
  cris_reinsert_addr,
  0,
  0,
  cris_breakpoint_at,
  cris_breakpoint_at,
  cris_insert_watchpoint,
  cris_insert_watchpoint,
  cris_remove_watchpoint,
  cris_remove_watchpoint,
  cris_stopped_by_watchpoint,
  cris_stopped_by_watchpoint,
  cris_stopped_data_address,
  cris_stopped_data_address,
};
};
 
 

powered by: WebSVN 2.1.0

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