Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC] New GDB Port CR16
@ 2012-08-27  6:37 Kaushik Phatak
  2012-08-27 16:21 ` Yao Qi
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Kaushik Phatak @ 2012-08-27  6:37 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 2354 bytes --]

Hi,

Please find attached a patch that adds support for the National Semiconductor CR16 
architecture to GDB. The sim patch is already present in the sources. This patch
enhances the sim to support breakpoints for sim based debugging.

I had earlier posted a patch to fix the build failures in CR16 sim,
http://sourceware.org/ml/gdb-patches/2012-05/msg00342.html
However these were already fixed by Mike Frysinger,
http://sourceware.org/bugzilla/show_bug.cgi?id=12862

This fixed the build failures, but the target was not emulating the correct
system calls. This patch should fix this problem by regenerating nltvals.def 
using gennltvals.sh with the following libgloss additions to Newlib posted 
recently,
http://sourceware.org/ml/newlib/2012/msg00319.html

The attached patch includes the expected nltvals.def file changes, however I 
may have not run the script correctly. Please let me know if this is ok.

Additionally, the port uses two functions from the disassembler in 
opcodes/cr16-dis.c. The static declarations have been removed from these. These
are added to the patch below. Do I need to copy that hunk to binutils mailing
list?

The port uses basic structure of the Renesas RX port and some concepts borrowed 
from the ARM port. Kindly review the same and let me know if further modifications
are required.

Additional Information on CR16 target:
The CR16 target saves the return address (right shifted by 1) onto the RA
register, which is later pushed onto the stack for leaf calls. The unwinder
takes care of this in the frame_prev_register call.
The CR16 target has a combination of 16 and 32 bit registers. R0 to R11 are
16 bits wide and can be accessed as 16 bit or 32 bit (register pair).
R12, R13, RA and SP are 32 bit registers.


2012-08-24 Kaushik Phatak  <kaushik.phatak@kpitcummins.com>

gdb/ChangeLog:
	* configure.tgt (cr16-*-elf): New target.
	* cr16-tdep.c: New file.

sim/cr16/ChangeLog:
	* interp.c (sim_complete_command): New stub function.
	* cr16_sim.h : Add defines for TRAP handling
	* simops.c: Breakpoint handling code

opcodes/ChangeLog:
	* cr16-dis.c (match_opcode): Remove static function
	declaration.
	(make_instruction): Likewise.


Thanks & Best Regards,
Kaushik
kaushik.phatak@kpitcummins.com
KPIT Cummins Infosystems Ltd
www.kpitcummins.com


[-- Attachment #2: cr16_gdb.diff --]
[-- Type: application/octet-stream, Size: 34370 bytes --]

--- gdb_src.orig/sim/common/gennltvals.sh	2012-03-19 10:24:48.000000000 +0530
+++ ./gdb_src/sim/common/gennltvals.sh	2012-08-17 15:35:15.000000000 +0530
@@ -41,7 +41,7 @@ $shell ${srccom}/gentvals.sh $target sys
 # OBSOLETE $shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
 # OBSOLETE 	"syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
 
-dir=libgloss target=cr16
+dir=libgloss/cr16/sys target=cr16
 $shell ${srccom}/gentvals.sh $target sys ${srcroot}/$dir \
 	"syscall.h" 'SYS_[_[:alnum:]]*' "${cpp}"
 
--- gdb_src.orig/sim/common/nltvals.def	2011-05-26 23:50:13.000000000 +0530
+++ ./gdb_src/sim/common/nltvals.def	2012-08-17 15:36:39.000000000 +0530
@@ -218,30 +218,34 @@
 #ifdef sys_defs
 /* from syscall.h */
 /* begin cr16 sys target macros */
- { "SYS_argc", 22 },
- { "SYS_argn", 24 },
- { "SYS_argnlen", 23 },
- { "SYS_argv", 13 },
- { "SYS_argvlen", 12 },
- { "SYS_chdir", 14 },
- { "SYS_chmod", 16 },
- { "SYS_close", 3 },
- { "SYS_exit", 1 },
- { "SYS_fstat", 10 },
- { "SYS_getpid", 8 },
- { "SYS_gettimeofday", 19 },
- { "SYS_kill", 9 },
- { "SYS_link", 21 },
- { "SYS_lseek", 6 },
- { "SYS_open", 2 },
- { "SYS_read", 4 },
- { "SYS_reconfig", 25 },
- { "SYS_stat", 15 },
- { "SYS_time", 18 },
- { "SYS_times", 20 },
- { "SYS_unlink", 7 },
- { "SYS_utime", 17 },
- { "SYS_write", 5 },
+ { "SYS_ARG", 24 },
+ { "SYS_chdir", 12 },
+ { "SYS_chmod", 15 },
+ { "SYS_chown", 16 },
+ { "SYS_close", 0x402 },
+ { "SYS_create", 8 },
+ { "SYS_execv", 11 },
+ { "SYS_execve", 59 },
+ { "SYS_exit", 0x410 },
+ { "SYS_fork", 2 },
+ { "SYS_fstat", 22 },
+ { "SYS_getpid", 20 },
+ { "SYS_isatty", 21 },
+ { "SYS_kill", 60 },
+ { "SYS_link", 9 },
+ { "SYS_lseek", 0x405 },
+ { "SYS_mknod", 14 },
+ { "SYS_open", 0x401 },
+ { "SYS_pipe", 42 },
+ { "SYS_read", 0x403 },
+ { "SYS_rename", 0x406 },
+ { "SYS_stat", 38 },
+ { "SYS_time", 0x300 },
+ { "SYS_unlink", 0x407 },
+ { "SYS_utime", 201 },
+ { "SYS_wait", 202 },
+ { "SYS_wait4", 7 },
+ { "SYS_write", 0x404 },
 /* end cr16 sys target macros */
 #endif
 #endif
--- gdb_src.orig/sim/cr16/cr16_sim.h	2012-01-04 13:58:07.000000000 +0530
+++ ./gdb_src/sim/cr16/cr16_sim.h	2012-08-24 17:22:24.000000000 +0530
@@ -472,3 +472,9 @@ extern void write_longlong PARAMS ((uint
    PSR is masked for zero bits. */
 
 extern creg_t move_to_cr (int cr, creg_t mask, creg_t val, int psw_hw_p);
+
+#ifndef SIGTRAP
+#define SIGTRAP 5
+#endif
+/* Special purpose trap  */
+#define TRAP_BREAKPOINT 8
--- gdb_src.orig/sim/cr16/interp.c	2012-06-18 05:04:17.000000000 +0530
+++ ./gdb_src/sim/cr16/interp.c	2012-08-17 15:41:35.000000000 +0530
@@ -1192,7 +1192,11 @@ sim_resume (SIM_DESC sd, int step, int s
       iaddr = imem_addr ((uint32)PC);
       if (iaddr == State.mem.fault)
         {
+#ifdef SIGBUS
           State.exception = SIGBUS;
+#else
+          State.exception = SIGSEGV;
+#endif
           break;
         }
  
@@ -1548,6 +1552,11 @@ sim_store_register (sd, rn, memory, leng
   return size;
 }
 
+char **
+sim_complete_command (SIM_DESC sd, char *text, char *word)
+{
+  return NULL;
+}
 
 void
 sim_do_command (sd, cmd)
--- gdb_src.orig/sim/cr16/simops.c	2012-01-04 13:58:07.000000000 +0530
+++ ./gdb_src/sim/cr16/simops.c	2012-08-17 16:34:11.000000000 +0530
@@ -5059,6 +5059,8 @@ OP_14C_14 ()
 void
 OP_C_C ()
 {
+  uint32 tmp;
+  uint16 a;
   trace_input ("excp", OP_CONSTANT4, OP_VOID, OP_VOID);
   switch (OP[0])
     {
@@ -5465,9 +5467,24 @@ OP_C_C ()
 #endif
 	    
 	  default:
+	    a = OP[0];
+	    switch(a)
+	    {
+	  case  TRAP_BREAKPOINT:
+	    State.exception = SIGTRAP;
+	    tmp = (PC);
+	    JMP(tmp);
+	    trace_output_void ();
+	  break;
+	  case  SIGTRAP:  // supervisor call ?
+	    State.exception = SIG_CR16_EXIT;
+	    trace_output_void ();
+	  break;
+	  default:
 	    cr16_callback->error (cr16_callback, "Unknown syscall %d", FUNC);
+	  break;
+	    }
 	  }
-
 	if ((uint16) result == (uint16) -1)
 	  RETERR (cr16_callback->get_errno(cr16_callback));
 	else
diff -uprN gdb_src.orig/opcodes/cr16-dis.c ./gdb_src/opcodes/cr16-dis.c
--- gdb_src.orig/opcodes/cr16-dis.c	2012-05-17 20:43:25.000000000 +0530
+++ ./gdb_src/opcodes/cr16-dis.c	2012-08-17 16:10:44.000000000 +0530
@@ -317,7 +317,9 @@ build_mask (void)
 
 /* Search for a matching opcode. Return 1 for success, 0 for failure.  */
 
-static int
+int match_opcode (void);
+
+int
 match_opcode (void)
 {
   unsigned long mask;
@@ -734,7 +736,9 @@ print_arguments (ins *currentInsn, bfd_v
 
 /* Build the instruction's arguments.  */
 
-static void
+void make_instruction (void);
+
+void
 make_instruction (void)
 {
   int i;
Common subdirectories: gdb_src.orig/gdb/cli and ./gdb_src/gdb/cli
Common subdirectories: gdb_src.orig/gdb/common and ./gdb_src/gdb/common
Common subdirectories: gdb_src.orig/gdb/config and ./gdb_src/gdb/config
diff -upN gdb_src.orig/gdb/configure.tgt ./gdb_src/gdb/configure.tgt
--- gdb_src.orig/gdb/configure.tgt	2012-08-02 01:18:44.000000000 +0530
+++ ./gdb_src/gdb/configure.tgt	2012-08-17 16:01:37.000000000 +0530
@@ -116,6 +116,13 @@ bfin-*-*)
 	gdb_sim=../sim/bfin/libsim.a
 	;;
 
+cr16*-*-*)
+	# Target: CR16 processor
+	gdb_target_obs="cr16-tdep.o"
+	gdb_sim=../sim/cr16/libsim.a
+	build_gdbserver=yes
+	;;
+
 cris*)
 	# Target: CRIS
 	gdb_target_obs="cris-tdep.o solib-svr4.o"
Common subdirectories: gdb_src.orig/gdb/contrib and ./gdb_src/gdb/contrib
diff -upN gdb_src.orig/gdb/cr16-tdep.c ./gdb_src/gdb/cr16-tdep.c
--- gdb_src.orig/gdb/cr16-tdep.c	1970-01-01 05:30:00.000000000 +0530
+++ ./gdb_src/gdb/cr16-tdep.c	2012-08-27 10:10:22.000000000 +0530
@@ -0,0 +1,891 @@
+/* Target-dependent code for the Sitel CR16 for GDB, the GNU debugger.
+ 
+   Copyright (C) 2012 Free Software Foundation, Inc.
+ 
+   Contributed by KPIT Cummins Infosystems Limited.
+   This file is part of GDB.
+
+  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
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+ 
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+ 
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "prologue-value.h"
+#include "target.h"
+#include "regcache.h"
+#include "opcode/cr16.h"
+#include "dis-asm.h"
+#include "gdbtypes.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "frame-base.h"
+#include "value.h"
+#include "gdbcore.h"
+#include "dwarf2-frame.h"
+#include "gdb/sim-cr16.h"
+#include "elf/cr16.h"
+#include "elf-bfd.h"
+
+typedef unsigned short wordU;
+extern wordU words[3];
+extern ULONGLONG allWords;
+extern ins currInsn;
+
+/* Architecture specific data.  */
+struct gdbarch_tdep
+{
+  /* The ELF header flags specify the multilib used.  */
+  int elf_flags;
+};
+
+/* Certain important register numbers.  */
+enum
+{
+  CR16_R0_REGNUM = 0,
+  CR16_R7_REGNUM = 7,
+  CR16_R12_REGNUM = 12,
+  CR16_FP_REGNUM = 13,
+  CR16_RA_REGNUM = 14,
+  CR16_SP_REGNUM = 15,
+  CR16_PC_REGNUM = 16,
+  CR16_NUM_REGS = 22
+};
+
+/* This structure holds the results of a prologue analysis.  */
+struct cr16_prologue
+{
+  /* The offset from the frame base to the stack pointer --- always
+     zero or negative.
+
+     Calling this a "size" is a bit misleading, but given that the
+     stack grows downwards, using offsets for everything keeps one
+     from going completely sign-crazy: you never change anything's
+     sign for an ADD instruction; always change the second operand's
+     sign for a SUB instruction; and everything takes care of
+     itself.  */
+  int frame_size;
+
+  /* Non-zero if this function has initialized the frame pointer from
+     the stack pointer, zero otherwise.  */
+  int has_frame_ptr;
+
+  /* If has_frame_ptr is non-zero, this is the offset from the frame
+     base to where the frame pointer points.  This is always zero or
+     negative.  */
+  int frame_ptr_offset;
+
+  /* The address of the first instruction at which the frame has been
+     set up and the arguments are where the debug info says they are
+     --- as best as we can tell.  */
+  CORE_ADDR prologue_end;
+
+  /* reg_offset[R] is the offset from the CFA at which register R is
+     saved, or 1 if register R has not been saved.  (Real values are
+     always zero or negative.)  */
+  int reg_offset[CR16_NUM_REGS];
+};
+
+/* Implement the "register_name" gdbarch method.  */
+static const char *
+cr16_register_name (struct gdbarch *gdbarch, int regnr)
+{
+  static const char *const reg_names[] = {
+    "r0",
+    "r1",
+    "r2",
+    "r3",
+    "r4",
+    "r5",
+    "r6",
+    "r7",
+    "r8",
+    "r9",
+    "r10",
+    "r11",
+    "r12",
+    "r13",
+    "ra",
+    "sp",
+    "pc",
+    "isp",
+    "usp",
+    "intbase",
+    "psr",
+    "cfg"
+  };
+
+  return reg_names[regnr];
+}
+
+/* Implement the "register_type" gdbarch method.  */
+static struct type *
+cr16_register_type (struct gdbarch *gdbarch, int reg_nr)
+{
+  switch (reg_nr)
+    {
+    case CR16_PC_REGNUM:	/* Note:PC in CR16 is of 24 bits */
+      return builtin_type (gdbarch)->builtin_func_ptr;
+
+    case CR16_RA_REGNUM:	/* Return address reg */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case CR16_FP_REGNUM:	/*Frame Pointer reg */
+    case CR16_SP_REGNUM:	/*Stack Pointer reg */
+      return builtin_type (gdbarch)->builtin_data_ptr;
+      break;
+
+    case SIM_CR16_ISP_REGNUM:
+    case SIM_CR16_USP_REGNUM:
+    case SIM_CR16_INTBASE_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    case SIM_CR16_PSR_REGNUM:
+    case SIM_CR16_CFG_REGNUM:
+      return builtin_type (gdbarch)->builtin_uint32;
+      break;
+
+    case SIM_CR16_R0_REGNUM:
+    case SIM_CR16_R1_REGNUM:
+    case SIM_CR16_R2_REGNUM:
+    case SIM_CR16_R3_REGNUM:
+    case SIM_CR16_R4_REGNUM:
+    case SIM_CR16_R5_REGNUM:
+    case SIM_CR16_R6_REGNUM:
+    case SIM_CR16_R7_REGNUM:
+    case SIM_CR16_R8_REGNUM:
+    case SIM_CR16_R9_REGNUM:
+    case SIM_CR16_R10_REGNUM:
+    case SIM_CR16_R11_REGNUM:
+      return builtin_type (gdbarch)->builtin_int16;
+      break;
+
+    case SIM_CR16_R12_REGNUM:
+      return builtin_type (gdbarch)->builtin_int32;
+      break;
+
+    default:
+      printf
+	("\nRegister Type not supported\nFunction : cr16_register_type\n");
+      return 0;
+      break;
+    }
+}
+
+/* Function for finding saved registers in a 'struct pv_area'; this
+   function is passed to pv_area_scan.
+ 
+   If VALUE is a saved register, ADDR says it was saved at a constant
+   offset from the frame base, and SIZE indicates that the whole
+   register was saved, record its offset.  */
+static void
+check_for_saved (void *result_untyped, pv_t addr, CORE_ADDR size, pv_t value)
+{
+  struct cr16_prologue *result = (struct cr16_prologue *) result_untyped;
+
+  if (value.kind == pvk_register
+      && value.k == 0
+      && pv_is_register (addr, CR16_SP_REGNUM)
+      && size == register_size (target_gdbarch, value.reg))
+    result->reg_offset[value.reg] = addr.k;
+}
+
+/* Define a "handle" struct for fetching the next opcode.  */
+struct cr16_get_opcode_byte_handle
+{
+  CORE_ADDR pc;
+};
+
+/* Use functions from opcodes/cr16-dis.c by making them non-static*/
+extern void make_instruction (void);
+extern int match_opcode (void);
+extern void get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info);
+
+/* Analyze a prologue starting at START_PC, going no further than
+   LIMIT_PC.  Fill in RESULT as appropriate.  */
+static void
+cr16_analyze_prologue (CORE_ADDR start_pc,
+		       CORE_ADDR limit_pc, struct cr16_prologue *result)
+{
+  CORE_ADDR pc, next_pc;
+  gdb_byte buf[6];
+  char insn_byte1, insn_byte2;
+  int rn;
+  int length;
+  pv_t reg[CR16_NUM_REGS];
+  struct pv_area *stack;
+  struct cleanup *back_to;
+  CORE_ADDR after_last_frame_setup_insn = start_pc;
+  int is_decoded;               /* Nonzero means instruction has a match.  */
+
+  memset (result, 0, sizeof (*result));
+
+  for (rn = 0; rn < CR16_NUM_REGS; rn++)
+    {
+      reg[rn] = pv_register (rn, 0);
+      result->reg_offset[rn] = 1;
+    }
+
+  stack = make_pv_area (CR16_SP_REGNUM, gdbarch_addr_bit (target_gdbarch));
+  back_to = make_cleanup_free_pv_area (stack);
+
+  pc = start_pc;
+  while (pc < limit_pc)
+    {
+      target_read_memory (pc, buf, 6);	// read 6 bytes, max 48 bit opcode
+      words[0] = buf[1] << 8 | buf[0];
+      words[1] = buf[3] << 8 | buf[2];
+      words[2] = buf[5] << 8 | buf[4];
+      allWords =
+	((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) +
+	words[2];
+
+      /* Find a matching opcode in table.  */
+      is_decoded = match_opcode ();
+      make_instruction ();
+      length = currInsn.size;
+      next_pc = pc + length;
+      insn_byte1 = (words[0] >> 8) & 0xFF;
+
+      if (insn_byte1 == 0x01)	// PUSH
+	{
+	  int r1, r2;
+	  int r;
+	  insn_byte2 = words[0];
+
+	  if (insn_byte2 & 0x80)	// Save RA reg
+	    {
+	      reg[CR16_SP_REGNUM] = pv_add_constant (reg[CR16_SP_REGNUM], -4);
+	      pv_area_store (stack, reg[CR16_SP_REGNUM], 4,
+			     reg[CR16_RA_REGNUM]);
+	    }
+
+	  r1 = insn_byte2 & 0x0F;	// Start Register
+	  r2 = ((insn_byte2 & 0x70) >> 4);	//3 bit imm count
+	  r2 = r2 + r1 + 1;	// 3 bit count is 1 to 8
+
+	  for (r = r1; r < r2; r++)
+	    {
+	      if (r >= CR16_R12_REGNUM)
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -4);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 4, reg[r]);
+		  r++;
+		}
+	      else
+		{
+		  reg[CR16_SP_REGNUM] =
+		    pv_add_constant (reg[CR16_SP_REGNUM], -2);
+		  pv_area_store (stack, reg[CR16_SP_REGNUM], 2, reg[r]);
+		}
+	    }
+	  after_last_frame_setup_insn = next_pc;
+	}
+
+      else if (insn_byte1 == 0x60)	// Add constant to SP
+	{
+	  int rdst;
+	  signed short addend;
+	  insn_byte2 = words[0];
+	  rdst = insn_byte2 & 0x0F;	// mask upper nibble 
+	  if (rdst == CR16_SP_REGNUM)	// adding to SP?
+	    {
+	      if (length == 2)
+		{
+		  addend = (insn_byte2 & 0xF0) >> 4;	// use upper nibble
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      if (length == 4)
+		{
+		  addend = words[1];
+		  reg[rdst] = pv_add_constant (reg[rdst], addend);
+		}
+	      after_last_frame_setup_insn = next_pc;
+	    }
+	}
+      else if (insn_byte1 == 0x55)	// MOVD
+	{
+	  int rdst, rsrc;
+	  insn_byte2 = words[0];
+	  rsrc = (insn_byte2 & 0xF0) >> 4;
+	  rdst = (insn_byte2 & 0x0F);
+	  reg[rdst] = reg[rsrc];
+	  if (rsrc == CR16_SP_REGNUM && rdst == CR16_FP_REGNUM)
+	    after_last_frame_setup_insn = next_pc;
+	}
+      else if (((insn_byte1 >> 4) & 0x0F) == 0xd)	// mask of lower nibble
+	{
+	  /* This moves an argument register to the stack.  Don't
+	     record it, but allow it to be a part of the prologue.  */
+	  after_last_frame_setup_insn = next_pc;
+	}
+      else
+	{
+	  break;		/* Terminate the prologue scan.  */
+	}
+
+      pc = next_pc;
+    }
+
+  /* Is the frame size (offset, really) a known constant?  */
+  if (pv_is_register (reg[CR16_SP_REGNUM], CR16_SP_REGNUM))
+    result->frame_size = reg[CR16_SP_REGNUM].k;
+
+  /* Was the frame pointer initialized?  */
+  if (pv_is_register (reg[CR16_FP_REGNUM], CR16_SP_REGNUM))
+    {
+      result->has_frame_ptr = 1;
+      result->frame_ptr_offset = reg[CR16_FP_REGNUM].k;
+    }
+
+  /* Record where all the registers were saved.  */
+  pv_area_scan (stack, check_for_saved, (void *) result);
+
+  result->prologue_end = after_last_frame_setup_insn;
+  do_cleanups (back_to);
+}
+
+
+/* Implement the "skip_prologue" gdbarch method.  */
+static CORE_ADDR
+cr16_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  const char *name;
+  CORE_ADDR func_addr, func_end;
+  struct cr16_prologue p;
+
+  /* Try to find the extent of the function that contains PC.  */
+  if (!find_pc_partial_function (pc, &name, &func_addr, &func_end))
+    return pc;
+
+  cr16_analyze_prologue (pc, func_end, &p);
+  return p.prologue_end;
+}
+
+/* Given a frame described by THIS_FRAME, decode the prologue of its
+   associated function if there is not cache entry as specified by
+   THIS_PROLOGUE_CACHE.  Save the decoded prologue in the cache and
+   return that struct as the value of this function.  */
+static struct cr16_prologue *
+cr16_analyze_frame_prologue (struct frame_info *this_frame,
+			     void **this_prologue_cache)
+{
+  if (!*this_prologue_cache)
+    {
+      CORE_ADDR func_start, stop_addr;
+
+      *this_prologue_cache = FRAME_OBSTACK_ZALLOC (struct cr16_prologue);
+
+      func_start = get_frame_func (this_frame);
+      stop_addr = get_frame_pc (this_frame);
+
+      /* If we couldn't find any function containing the PC, then
+         just initialize the prologue cache, but don't do anything.  */
+      if (!func_start)
+	stop_addr = func_start;
+
+      cr16_analyze_prologue (func_start, stop_addr, *this_prologue_cache);
+    }
+
+  return *this_prologue_cache;
+}
+
+/* Given the next frame and a prologue cache, return this frame's
+   base.  */
+static CORE_ADDR
+cr16_frame_base (struct frame_info *this_frame, void **this_prologue_cache)
+{
+  struct cr16_prologue *p
+    = cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+
+  /* In functions that use alloca, the distance between the stack
+     pointer and the frame base varies dynamically, so we can't use
+     the SP plus static information like prologue analysis to find the
+     frame base.  However, such functions must have a frame pointer,
+     to be able to restore the SP on exit.  So whenever we do have a
+     frame pointer, use that to find the base.  */
+  if (p->has_frame_ptr)
+    {
+      CORE_ADDR fp = get_frame_register_unsigned (this_frame, CR16_FP_REGNUM);
+      return fp - p->frame_ptr_offset;
+    }
+  else
+    {
+      CORE_ADDR sp = get_frame_register_unsigned (this_frame, CR16_SP_REGNUM);
+      return sp - p->frame_size;
+    }
+}
+
+/* Implement the "frame_this_id" method for unwinding frames.  */
+static void
+cr16_frame_this_id (struct frame_info *this_frame,
+		    void **this_prologue_cache, struct frame_id *this_id)
+{
+  *this_id =
+    frame_id_build (cr16_frame_base (this_frame, this_prologue_cache),
+		    get_frame_func (this_frame));
+}
+
+static struct value *
+cr16_frame_prev_register (struct frame_info *this_frame,
+			  void **this_prologue_cache, int regnum)
+{
+  struct cr16_prologue *p =
+    cr16_analyze_frame_prologue (this_frame, this_prologue_cache);
+  CORE_ADDR frame_base = cr16_frame_base (this_frame, this_prologue_cache);
+  int reg_size = register_size (get_frame_arch (this_frame), regnum);
+  ULONGEST ra_prev;
+
+  if (regnum == CR16_SP_REGNUM)
+    return frame_unwind_got_constant (this_frame, regnum, frame_base);
+
+  /* The call instruction has saved the return address on the RA register,
+     CR16_R13_REGNUM. So, we need not adjust anything directly. We will 
+     analyze prologue as this RA register is pushed onto stack for further
+     leaf function calls to work */
+  else if (regnum == CR16_PC_REGNUM)
+    {
+      ra_prev = frame_unwind_register_unsigned (this_frame, CR16_RA_REGNUM);
+      ra_prev = ra_prev << 1;
+      return frame_unwind_got_constant (this_frame, CR16_PC_REGNUM, ra_prev);
+    }
+
+  /* If prologue analysis says we saved this register somewhere,
+     return a description of the stack slot holding it.  */
+  else if (p->reg_offset[regnum] != 1)
+    {
+      return frame_unwind_got_memory (this_frame, regnum,
+				      frame_base + p->reg_offset[regnum]);
+    }
+
+  /* Otherwise, presume we haven't changed the value of this
+     register, and get it from the next frame.  */
+  else
+    {
+      return frame_unwind_got_register (this_frame, regnum, regnum);
+    }
+}
+
+static const struct frame_unwind cr16_frame_unwind = {
+  NORMAL_FRAME,
+  default_frame_unwind_stop_reason,
+  cr16_frame_this_id,
+  cr16_frame_prev_register,
+  NULL,
+  default_frame_sniffer
+};
+
+/* Implement the "unwind_pc" gdbarch method.  */
+static CORE_ADDR
+cr16_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST pc;
+
+  pc = frame_unwind_register_unsigned (this_frame, CR16_PC_REGNUM);
+  return pc;
+}
+
+/* Implement the "unwind_sp" gdbarch method.  */
+static CORE_ADDR
+cr16_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  ULONGEST sp;
+
+  sp = frame_unwind_register_unsigned (this_frame, CR16_SP_REGNUM);
+  return sp;
+}
+
+/* Implement the "dummy_id" gdbarch method.  */
+static struct frame_id
+cr16_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
+{
+  return
+    frame_id_build (get_frame_register_unsigned (this_frame, CR16_SP_REGNUM),
+		    get_frame_pc (this_frame));
+}
+
+/* Implement the "push_dummy_call" gdbarch method.  */
+static CORE_ADDR
+cr16_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
+		      struct regcache *regcache, CORE_ADDR bp_addr, int nargs,
+		      struct value **args, CORE_ADDR sp, int struct_return,
+		      CORE_ADDR struct_addr)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  int write_pass;
+  int sp_off = 0;
+  CORE_ADDR cfa;
+  int num_register_candidate_args;
+
+  struct type *func_type = value_type (function);
+
+  /* Dereference function pointer types.  */
+  while (TYPE_CODE (func_type) == TYPE_CODE_PTR)
+    func_type = TYPE_TARGET_TYPE (func_type);
+
+  /* The end result had better be a function or a method.  */
+  gdb_assert (TYPE_CODE (func_type) == TYPE_CODE_FUNC
+	      || TYPE_CODE (func_type) == TYPE_CODE_METHOD);
+
+  /* Functions with a variable number of arguments have all of their
+     variable arguments and the last non-variable argument passed
+     on the stack.
+
+     Otherwise, we can pass up to four arguments on the stack.
+
+     Once computed, we leave this value alone.  I.e. we don't update
+     it in case of a struct return going in a register or an argument
+     requiring multiple registers, etc.  We rely instead on the value
+     of the ``arg_reg'' variable to get these other details correct.  */
+
+  if (TYPE_VARARGS (func_type))
+    num_register_candidate_args = TYPE_NFIELDS (func_type) - 1;
+  else
+    num_register_candidate_args = 4;
+
+  /* We make two passes; the first does the stack allocation,
+     the second actually stores the arguments.  */
+  for (write_pass = 0; write_pass <= 1; write_pass++)
+    {
+      int i;
+      int arg_reg = CR16_R0_REGNUM;
+
+      if (write_pass)
+	sp = align_down (sp - sp_off, 4);
+      sp_off = 0;
+
+      if (struct_return)
+	{
+	  struct type *return_type = TYPE_TARGET_TYPE (func_type);
+
+	  gdb_assert (TYPE_CODE (return_type) == TYPE_CODE_STRUCT
+		      || TYPE_CODE (func_type) == TYPE_CODE_UNION);
+
+	  if (TYPE_LENGTH (return_type) > 16
+	      || TYPE_LENGTH (return_type) % 4 != 0)
+	    {
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	}
+
+      /* Push the arguments.  */
+      for (i = 0; i < nargs; i++)
+	{
+	  struct value *arg = args[i];
+	  const gdb_byte *arg_bits = value_contents_all (arg);
+	  struct type *arg_type = check_typedef (value_type (arg));
+	  ULONGEST arg_size = TYPE_LENGTH (arg_type);
+
+	  if (i == 0 && struct_addr != 0 && !struct_return
+	      && TYPE_CODE (arg_type) == TYPE_CODE_PTR
+	      && extract_unsigned_integer (arg_bits, 4,
+					   byte_order) == struct_addr)
+	    {
+	      /* This argument represents the address at which C++ (and
+	         possibly other languages) store their return value.
+	         Put this value in R15.  */
+	      if (write_pass)
+		regcache_cooked_write_unsigned (regcache, CR16_R12_REGNUM,
+						struct_addr);
+	    }
+	  else if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT
+		   && TYPE_CODE (arg_type) != TYPE_CODE_UNION)
+	    {
+	      /* Argument is a scalar.  */
+	      if (arg_size == 8)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM - 1)
+		    {
+		      /* If argument registers are going to be used to pass
+		         an 8 byte scalar, the ABI specifies that two registers
+		         must be available.  */
+		      if (write_pass)
+			{
+			  regcache_cooked_write_unsigned (regcache, arg_reg,
+							  extract_unsigned_integer
+							  (arg_bits, 4,
+							   byte_order));
+			  regcache_cooked_write_unsigned (regcache,
+							  arg_reg + 1,
+							  extract_unsigned_integer
+							  (arg_bits + 4, 4,
+							   byte_order));
+			}
+		      arg_reg += 2;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      /* Otherwise, pass the 8 byte scalar on the stack.  */
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, 8);
+		      sp_off += 8;
+		    }
+		}
+	      else
+		{
+		  ULONGEST u;
+
+		  gdb_assert (arg_size <= 4);
+
+		  u =
+		    extract_unsigned_integer (arg_bits, arg_size, byte_order);
+
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM)
+		    {
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg, u);
+		      arg_reg += 1;
+		    }
+		  else
+		    {
+		      int p_arg_size = 4;
+
+		      if (TYPE_PROTOTYPED (func_type)
+			  && i < TYPE_NFIELDS (func_type))
+			{
+			  struct type *p_arg_type =
+			    TYPE_FIELD_TYPE (func_type, i);
+			  p_arg_size = TYPE_LENGTH (p_arg_type);
+			}
+
+		      sp_off = align_up (sp_off, p_arg_size);
+
+		      if (write_pass)
+			write_memory_unsigned_integer (sp + sp_off,
+						       p_arg_size, byte_order,
+						       u);
+		      sp_off += p_arg_size;
+		    }
+		}
+	    }
+	  else
+	    {
+	      /* Argument is a struct or union.  Pass as much of the struct
+	         in registers, if possible.  Pass the rest on the stack.  */
+	      while (arg_size > 0)
+		{
+		  if (i < num_register_candidate_args
+		      && arg_reg <= CR16_R7_REGNUM
+		      && arg_size <= 4 * (CR16_R7_REGNUM - arg_reg + 1)
+		      && arg_size % 4 == 0)
+		    {
+		      int len = min (arg_size, 4);
+
+		      if (write_pass)
+			regcache_cooked_write_unsigned (regcache, arg_reg,
+							extract_unsigned_integer
+							(arg_bits, len,
+							 byte_order));
+		      arg_bits += len;
+		      arg_size -= len;
+		      arg_reg++;
+		    }
+		  else
+		    {
+		      sp_off = align_up (sp_off, 4);
+		      if (write_pass)
+			write_memory (sp + sp_off, arg_bits, arg_size);
+		      sp_off += align_up (arg_size, 4);
+		      arg_size = 0;
+		    }
+		}
+	    }
+	}
+    }
+
+  /* Keep track of the stack address prior to pushing the return address.
+     This is the value that we'll return.  */
+  cfa = sp;
+
+  /* Push the return address.  */
+  sp = sp - 4;
+  write_memory_unsigned_integer (sp, 4, byte_order, bp_addr);
+
+  /* Update the stack pointer.  */
+  regcache_cooked_write_unsigned (regcache, CR16_SP_REGNUM, sp);
+
+  return cfa;
+}
+
+/* Implement the "return_value" gdbarch method.  */
+static enum return_value_convention
+cr16_return_value (struct gdbarch *gdbarch,
+		   struct type *func_type,
+		   struct type *valtype,
+		   struct regcache *regcache,
+		   gdb_byte * readbuf, const gdb_byte * writebuf)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  ULONGEST valtype_len = TYPE_LENGTH (valtype);
+
+  if (TYPE_LENGTH (valtype) > 16
+      || ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
+	   || TYPE_CODE (valtype) == TYPE_CODE_UNION)
+	  && TYPE_LENGTH (valtype) % 4 != 0))
+    return RETURN_VALUE_STRUCT_CONVENTION;
+
+  if (readbuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  regcache_cooked_read_unsigned (regcache, argreg, &u);
+	  store_unsigned_integer (readbuf + offset, len, byte_order, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  if (writebuf)
+    {
+      ULONGEST u;
+      int argreg = CR16_R0_REGNUM;
+      int offset = 0;
+
+      while (valtype_len > 0)
+	{
+	  int len = min (valtype_len, 4);
+
+	  u = extract_unsigned_integer (writebuf + offset, len, byte_order);
+	  regcache_cooked_write_unsigned (regcache, argreg, u);
+	  valtype_len -= len;
+	  offset += len;
+	  argreg++;
+	}
+    }
+
+  return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* Implement the "breakpoint_from_pc" gdbarch method.  */
+static const gdb_byte *
+cr16_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR * pcptr,
+			 int *lenptr)
+{
+  /* opcode of excp instruction for bpt is 0x00C8, however for uclinux we use
+     excp flg (0x00C7) to insert a breakpoint. The excp bpt requires external
+     hardware support for breakpoints to work on CR16 target. Software based
+     breakpoints are implemented in the kernel using excp flg and tested on
+     the SC14452 target. Use 0x00C7 with gdbserver/kernel and 0x00C8 for sim/ELF
+     We represent the breakpoint in little endian format since CR16 supports 
+     only little endian.
+   */
+  static gdb_byte breakpoint[] = { 0xC8, 0x00 };
+  *lenptr = sizeof breakpoint;
+  return breakpoint;
+}
+
+
+
+/* Allocate and initialize a gdbarch object.  */
+static struct gdbarch *
+cr16_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+  struct gdbarch *gdbarch;
+  struct gdbarch_tdep *tdep;
+  int elf_flags;
+
+  /* Extract the elf_flags if available.  */
+  if (info.abfd != NULL
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_flags = elf_elfheader (info.abfd)->e_flags;
+  else
+    elf_flags = 0;
+
+  /* Try to find the architecture in the list of already defined
+     architectures.  */
+  for (arches = gdbarch_list_lookup_by_info (arches, &info);
+       arches != NULL;
+       arches = gdbarch_list_lookup_by_info (arches->next, &info))
+    {
+      if (gdbarch_tdep (arches->gdbarch)->elf_flags != elf_flags)
+	continue;
+
+      return arches->gdbarch;
+    }
+  /* None found, create a new architecture from the information
+     provided.  */
+  tdep = (struct gdbarch_tdep *) xmalloc (sizeof (struct gdbarch_tdep));
+  gdbarch = gdbarch_alloc (&info, tdep);
+  tdep->elf_flags = elf_flags;
+
+  set_gdbarch_num_regs (gdbarch, CR16_NUM_REGS);
+  set_gdbarch_num_pseudo_regs (gdbarch, 0);
+  set_gdbarch_register_name (gdbarch, cr16_register_name);
+  set_gdbarch_register_type (gdbarch, cr16_register_type);
+  set_gdbarch_pc_regnum (gdbarch, CR16_PC_REGNUM);
+  set_gdbarch_sp_regnum (gdbarch, CR16_SP_REGNUM);
+  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  set_gdbarch_breakpoint_from_pc (gdbarch, cr16_breakpoint_from_pc);
+  set_gdbarch_skip_prologue (gdbarch, cr16_skip_prologue);
+
+  /* Passing NULL  values in the following two functions
+     for the time being, to fix later  */
+  set_gdbarch_print_insn (gdbarch, print_insn_cr16);
+  set_gdbarch_unwind_pc (gdbarch, cr16_unwind_pc);
+  set_gdbarch_unwind_sp (gdbarch, cr16_unwind_sp);
+
+  /* Methods for saving / extracting a dummy frame's ID.
+     The ID's stack address must match the SP value returned by
+     PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos.  */
+  set_gdbarch_dummy_id (gdbarch, cr16_dummy_id);
+  set_gdbarch_push_dummy_call (gdbarch, cr16_push_dummy_call);
+  /* Target builtin data types.  */
+  set_gdbarch_char_signed (gdbarch, 8);
+  set_gdbarch_short_bit (gdbarch, 16);
+
+  /* if we don't pass the option -mint32
+     To fix : add if else case depending on the option passed,
+     sp that we can have int size as 16 or 32 bits both. */
+  set_gdbarch_int_bit (gdbarch, 16);
+  set_gdbarch_long_bit (gdbarch, 32);
+  set_gdbarch_long_long_bit (gdbarch, 64);
+  set_gdbarch_float_bit (gdbarch, 32);
+
+  set_gdbarch_ptr_bit (gdbarch, 32);
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  frame_unwind_append_unwinder (gdbarch, &cr16_frame_unwind);
+  set_gdbarch_return_value (gdbarch, cr16_return_value);
+
+  return gdbarch;
+
+}
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_cr16_tdep;
+
+/* Register the above initialization routine.  */
+void
+_initialize_cr16_tdep (void)
+{
+  register_gdbarch_init (bfd_arch_cr16, cr16_gdbarch_init);
+}
diff -upN gdb_src.orig/configure ./gdb_src/configure
--- gdb_src.orig/configure	2012-06-28 17:20:52.000000000 +0530
+++ ./gdb_src/configure	2012-08-17 16:56:10.000000000 +0530
@@ -3447,7 +3447,7 @@ case "${target}" in
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
   cr16-*-*)
-    noconfigdirs="$noconfigdirs gdb"
+    noconfigdirs="$noconfigdirs target-libgloss"
     ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
diff -upN gdb_src.orig/configure.ac ./gdb_src/configure.ac
--- gdb_src.orig/configure.ac	2012-06-28 17:20:52.000000000 +0530
+++ ./gdb_src/configure.ac	2012-08-17 16:56:17.000000000 +0530
@@ -873,7 +873,7 @@ case "${target}" in
     noconfigdirs="$noconfigdirs target-libgloss gdb"
     ;;
   cr16-*-*)
-    noconfigdirs="$noconfigdirs gdb"
+    noconfigdirs="$noconfigdirs target-libgloss"
     ;;
   d10v-*-*)
     noconfigdirs="$noconfigdirs target-libgloss"
Common subdirectories: gdb_src.orig/cpu and ./gdb_src/cpu
Common subdirectories: gdb_src.orig/CVS and ./gdb_src/CVS
Common subdirectories: gdb_src.orig/etc and ./gdb_src/etc
Common subdirectories: gdb_src.orig/gdb and ./gdb_src/gdb
Common subdirectories: gdb_src.orig/include and ./gdb_src/include
Common subdirectories: gdb_src.orig/intl and ./gdb_src/intl
Common subdirectories: gdb_src.orig/libdecnumber and ./gdb_src/libdecnumber
Common subdirectories: gdb_src.orig/libiberty and ./gdb_src/libiberty
Common subdirectories: gdb_src.orig/opcodes and ./gdb_src/opcodes
Common subdirectories: gdb_src.orig/readline and ./gdb_src/readline
Common subdirectories: gdb_src.orig/sim and ./gdb_src/sim
Common subdirectories: gdb_src.orig/texinfo and ./gdb_src/texinfo

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2012-09-24 12:55 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-27  6:37 [RFC] New GDB Port CR16 Kaushik Phatak
2012-08-27 16:21 ` Yao Qi
2012-08-28 14:47   ` Kaushik Phatak
2012-08-29 22:14     ` Mike Frysinger
2012-08-30  5:23       ` Kaushik Phatak
2012-08-30  6:10         ` Mike Frysinger
2012-09-03  9:31         ` Pedro Alves
2012-09-04  3:52           ` Mike Frysinger
2012-09-04  6:50             ` Kaushik Phatak
2012-09-07 17:47               ` Pedro Alves
2012-09-11 13:16                 ` Kaushik Phatak
2012-09-11 19:02                   ` Mike Frysinger
2012-09-24 12:55                     ` Kaushik Phatak
2012-09-11 19:00               ` Mike Frysinger
2012-08-27 21:10 ` Mike Frysinger
2012-08-28 16:24 ` Pedro Alves
2012-08-30  4:49   ` Kaushik Phatak
2012-08-30  5:14     ` Yao Qi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox