public inbox for gdb@sourceware.org
 help / color / mirror / Atom feed
* ip2k port
@ 2003-09-15 19:39 Jafa
  2003-09-22  6:46 ` Andrew Cagney
  0 siblings, 1 reply; 2+ messages in thread
From: Jafa @ 2003-09-15 19:39 UTC (permalink / raw)
  To: gdb

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

Hi all,

Our internal QA has closed all remaining bugs that were files against the
ip2k port of GDB so I would like to get a first-pass review, heading towards
formally submitting the port.

One issue is the IGNORE_HELPER_CALL (used by the MIPS port as well) which is
currently a define rather a registerable function.

I welcome any feedback.

Thanks

Nick

[-- Attachment #2: ip2k-tdep.c --]
[-- Type: application/octet-stream, Size: 37228 bytes --]

/* Target-dependent code for Ubicom IP2K, for GDB.
   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.

   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 2 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, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "frame-base.h"
#include "trad-frame.h"
#include "gdbcore.h"
#include "inferior.h"
#include "symfile.h"
#include "arch-utils.h"
#include "regcache.h"
#include "gdb_string.h"

/* Threads.  */
#define IP2K_ISR_THREAD 1
#define IP2K_MAIN_THREAD 2
#define IP2K_VM_THREAD 3

/* Registers.  */
#define IP2K_NUM_NATIVE_REGS 256
#define IP2K_NUM_PSEUDO_REGS 5

#define IP2K_IPH_REGNUM 0x0004
#define IP2K_IPL_REGNUM 0x0005
#define IP2K_SPH_REGNUM 0x0006
#define IP2K_SPL_REGNUM 0x0007
#define IP2K_PCH_REGNUM 0x0008
#define IP2K_PCL_REGNUM 0x0009
#define IP2K_DPH_REGNUM 0x000C
#define IP2K_DPL_REGNUM 0x000D
#define IP2K_CALLH_REGNUM 0x007E
#define IP2K_CALLL_REGNUM 0x007F
#define IP2K_RETVAL_REGNUM 0x0080

#define IP2K_PC_REGNUM		(IP2K_NUM_NATIVE_REGS + 0)
#define IP2K_SP_REGNUM		(IP2K_NUM_NATIVE_REGS + 1)
#define IP2K_DP_REGNUM		(IP2K_NUM_NATIVE_REGS + 2)
#define IP2K_IP_REGNUM		(IP2K_NUM_NATIVE_REGS + 3)
#define IP2K_CALL_REGNUM	(IP2K_NUM_NATIVE_REGS + 4)

char *ip2k_register_names[] =
{
  " ", " ", "addrsel", "addrx",
  "iph", "ipl", "sph", "spl",
  "pch", "pcl", "wreg", "status",
  "dph", "dpl", "spdreg", "mulh",

  "addrh", "addrl", "datah", "datal",
  "intvech", "intvecl", "intspd", "intf",
  "inte", "inted", "fcfg", "tctrl",
  "xcfg", "emcfg", "ipch", "ipcl",

  "rain", "raout", "radir", "lfsrh",
  "rbin", "rbout", "rbdir", "lfsrl",
  "rcin", "rcout", "rcdir", "lfsra",
  "rdin", "rdout", "rddir", " ",

  "rein", "reout", "redir", " ",
  "rfin", "rfout", "rfdir", " ",
  " ", "rgout", "rgdir", " ",
  " ", " ", " ", " ",

  "rttmr", "rtcfg", "t0tmr", "t0cfg",
  "t1cnth", "t1cntl", "t1cap1h", "t1cap1l",
  "t1cap2h", "t1cap2l", "t1cmp1h", "t1cmp1l",
  "t1cfg1h", "t1cfg1l", "t1cfg2h", "t1cfg2l",

  "adch", "adcl", "adccfg", "adctmr",
  "t2cnth", "t2cntl", "t2cap1h", "t2cap1l",
  "t2cap2h", "t2cap2l", "t2cmp1h", "t2cmp1l",
  "t2cfg1h", "t2cfg1l", "t2cfg2h", "t2cfg2l",

  "s1tmrh", "s1tmrl", "s1tbufh", "s1tbufl",
  "s1tcfg", "s1rcnt", "s1rbufh", "s1rbufl",
  "s1rcfg", "s1rsync", "s1intf", "s1inte",
  "s1mode", "s1smask", "pspcfg", "cmpcfg",

  "s2tmrh", "s2tmrl", "s2tbufh", "s2tbufl",
  "s2tcfg", "s2rcnt", "s2rbufh", "s2rbufl",
  "s2rcfg", "s2rsync", "s2intf", "s2inte",
  "s2mode", "s2smask", "callh", "calll",

  "r80", "r81", "r82", "r83", "r84", "r85", "r86", "r87",
  "r88", "r89", "r8A", "r8B", "r8C", "r8D", "r8E", "r8F",
  "r90", "r91", "r92", "r93", "r94", "r95", "r96", "r97",
  "r98", "r99", "r9A", "r9B", "r9C", "r9D", "r9E", "r9F",

  "rA0", "rA1", "rA2", "rA3", "rA4", "rA5", "rA6", "rA7",
  "rA8", "rA9", "rAA", "rAB", "rAC", "rAD", "rAE", "rAF",
  "rB0", "rB1", "rB2", "rB3", "rB4", "rB5", "rB6", "rB7",
  "rB8", "rB9", "rBA", "rBB", "rBC", "rBD", "rBE", "rBF",

  "rC0", "rC1", "rC2", "rC3", "rC4", "rC5", "rC6", "rC7",
  "rC8", "rC9", "rCA", "rCB", "rCC", "rCD", "rCE", "rCF",
  "rD0", "rD1", "rD2", "rD3", "rD4", "rD5", "rD6", "rD7",
  "rD8", "rD9", "rDA", "rDB", "rDC", "rDD", "rDE", "rDF",

  "rE0", "rE1", "rE2", "rE3", "rE4", "rE5", "rE6", "rE7",
  "rE8", "rE9", "rEA", "rEB", "rEC", "rED", "rEE", "rEF",
  "rF0", "rF1", "rF2", "rF3", "rF4", "rF5", "rF6", "rF7",
  "rF8", "rF9", "rFA", "rFB", "rFC", "rFD", "rFE", "rFF",

  "pc", "sp", "dp", "ip", "call"
};

enum ip2k_func_type
{
  ip2k_func_type_normal = 0,
  ip2k_func_type_libgcc_stub,
  ip2k_func_type_libgcc_epilogue,
  ip2k_func_type_libgcc_indcall
};

/* Debug.  */
#define DEBUG_NONE 0
#define DEBUG_NORMAL 1
#define DEBUG_EXTRA 2
#define DEBUG_MAX 3
#define DEBUG_FRAME DEBUG_MAX
static int debug_level = DEBUG_NORMAL;

/* Frame info.  */
struct ip2k_unwind_cache
{
  CORE_ADDR entry_pc;
  CORE_ADDR current_pc;
  CORE_ADDR return_pc;
  CORE_ADDR entry_sp;
  CORE_ADDR normal_sp;
  CORE_ADDR current_sp;
  /* Table indicating the location of each and every register.  */
  struct trad_frame_saved_reg *saved_regs;
};

/* Prologue instructions - return address.
	push CALLL	(0x447f)
	push CALLH	(0x447e) */
static unsigned char ip2k_call_prologue_insns[] = { 0x44, 0x7f, 0x44, 0x7e };

/* Prologue instructions - frame pointer.
	push $fe	(0x44fe)
	mov W,SPL	(0x2007)
	mov $fe,W	(0x02fe)
	mov W,SPH	(0x2006)
	push $fd	(0x44fd)
	mov $fd,W	(0x02fd) */
static unsigned char ip2k_fp_prologue_insns[] =
  { 0x44, 0xfe, 0x20, 0x07, 0x02, 0xfe, 0x20, 0x06, 0x44, 0xfd, 0x02, 0xfd };

/* Prologue instructions - local variables (single).
	dec spl		(0x0e07) */
static unsigned char ip2k_local_1_prologue_insns[] = { 0x0e, 0x07 };

/* Prologue - local variables (multiple).
	mov W,#$xx	(0x7cxx)
	sub SPL,W	(0x0a07) */
static unsigned char ip2k_local_n_prologue_insns[] =
  { 0x7c, 0x00, 0x0a, 0x07 };


/* ip2k_try_pc_function_start.  */
static CORE_ADDR
ip2k_try_pc_function_start (CORE_ADDR pc)
{
  CORE_ADDR temp = get_pc_function_start (pc);
  if (temp != 0)
    return temp;

  printf_filtered ("warning: unable to find start of function of pc: 0x%08lx\n", pc);
  return pc;
}

/* ip2k_dptr_to_addr.  */
static CORE_ADDR
ip2k_dptr_to_addr (CORE_ADDR addr)
{
  if (addr == 0)
    return 0;

  if (addr & 0xFFFF0000)
    {
      warning ("invalid raw data pointer: 0x%08lx", addr);
      return 0;
    }
  if (ptid_get_pid (inferior_ptid) == IP2K_VM_THREAD)
    return (0x01400000 | (addr & 0x0000FFFF));
  else
    return (0x01000000 | (addr & 0x0000FFFF));
}

/* ip2k_iptr_to_addr.  */
static CORE_ADDR
ip2k_iptr_to_addr (CORE_ADDR addr)
{
  /* Note: 0 is a valid address!  */
  if (addr & 0xFFFF0000)
    {
      warning ("invalid raw instruction pointer: 0x%08lx", addr);
      return 0;
    }

  if (ptid_get_pid (inferior_ptid) == IP2K_VM_THREAD)
    return (0x02400000 | ((addr & 0x0000FFFF) << 1));
  else
    return (0x02000000 | ((addr & 0x0000FFFF) << 1));
}

/* ip2k_addr_to_dptr.  */
static CORE_ADDR
ip2k_addr_to_dptr (CORE_ADDR addr)
{
  if (addr == 0)
    return 0;

  if ((addr & 0xFF000000) != 0x01000000)
    {
      warning ("invalid data pointer: 0x%08lx", addr);
      return 0;
    }

  return (addr & 0x0000FFFF);
}

/* ip2k_addr_to_iptr.  */
static CORE_ADDR
ip2k_addr_to_iptr (CORE_ADDR addr)
{
  if (addr == 0)
    return 0;

  if ((addr & 0xFF000000) != 0x02000000)
    {
      warning ("invalid instruction pointer: 0x%08lx", addr);
      return 0;
    }

  return ((addr >> 1) & 0x0000FFFF);
}

/* ip2k_pointer_to_address.  */
static CORE_ADDR
ip2k_pointer_to_address (struct type *type, const void *buf)
{
  enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));
  CORE_ADDR addr = extract_unsigned_integer (buf, TYPE_LENGTH (type));

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_pointer_to_address\n");

  if ((target == TYPE_CODE_FUNC) || (target == TYPE_CODE_METHOD))
    addr = ip2k_iptr_to_addr (addr);
  else
    addr = ip2k_dptr_to_addr (addr);

  return addr;
}

/* ip2k_address_to_pointer.  */
static void
ip2k_address_to_pointer (struct type *type, void *buf, CORE_ADDR addr)
{
  enum type_code target = TYPE_CODE (TYPE_TARGET_TYPE (type));

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_address_to_pointer\n");

  if ((target == TYPE_CODE_FUNC) || (target == TYPE_CODE_METHOD))
    addr = ip2k_addr_to_iptr (addr);
  else
    addr = ip2k_addr_to_dptr (addr);

  store_unsigned_integer (buf, TYPE_LENGTH (type), addr);
}

/* ip2k_read_pc.  */
static CORE_ADDR
ip2k_read_pc (ptid_t ptid)
{
  ptid_t save_ptid;
  CORE_ADDR val;

  save_ptid = inferior_ptid;
  inferior_ptid = ptid;
  val = read_register (IP2K_PC_REGNUM);
  inferior_ptid = save_ptid;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_read_pc (0x%08lx)\n", ip2k_iptr_to_addr (val));

  return ip2k_iptr_to_addr (val);
}

/* ip2k_write_pc.  */
static void
ip2k_write_pc (CORE_ADDR val, ptid_t ptid)
{
  ptid_t save_ptid;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_write_pc\n");

  save_ptid = inferior_ptid;
  inferior_ptid = ptid;
  write_register (IP2K_PC_REGNUM, ip2k_addr_to_iptr (val));
  inferior_ptid = save_ptid;
}

/* ip2k_unwind_pc.  */
static CORE_ADDR
ip2k_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
  ULONGEST pc;
  frame_unwind_unsigned_register (next_frame, IP2K_PC_REGNUM, &pc);
  return ip2k_iptr_to_addr (pc);
}

/* ip2k_unwind_sp.  */
static CORE_ADDR
ip2k_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
  ULONGEST sp;
  frame_unwind_unsigned_register (next_frame, IP2K_SP_REGNUM, &sp);
  return ip2k_dptr_to_addr (sp);
}

/* ip2k_register_name.
   Given a register index, return the name of the corresponding register.  */
static const char *
ip2k_register_name (int regnum)
{
  if ((regnum < 0) || (regnum >= IP2K_NUM_NATIVE_REGS + IP2K_NUM_PSEUDO_REGS))
    {
      warning ("internal error: ip2k_register_name: invalid register: 0x%08x", regnum);
      return (NULL);
    }

  return (ip2k_register_names[regnum]);
}

/* Return the GDB type object for the "standard" data type
   of data in register N.  */
static struct type *
ip2k_register_type (struct gdbarch *gdbarch, int reg_nr)
{
  switch (reg_nr)
    {
    case IP2K_SP_REGNUM:
    case IP2K_DP_REGNUM:
    case IP2K_IP_REGNUM:
      return builtin_type_void_data_ptr;
    case IP2K_PC_REGNUM:
    case IP2K_CALL_REGNUM:
      return builtin_type_void_func_ptr;
    default:
      return builtin_type_uint8;
    }
}

/* ip2k_get_function_type_internal.  */
static inline enum ip2k_func_type
ip2k_get_function_type_internal (char *name)
{
  if (!strstr (name, "libgcc"))
    return ip2k_func_type_normal;

  if (strstr (name, "indcall"))
    return ip2k_func_type_libgcc_indcall;

  if (strstr (name, "add_sp"))
    return ip2k_func_type_libgcc_epilogue;

  return ip2k_func_type_libgcc_stub;
}

/* ip2k_get_function_type.  */
static enum ip2k_func_type
ip2k_get_function_type (CORE_ADDR pc, char *name)
{
  enum ip2k_func_type type;

  if (!name)
    find_pc_partial_function (pc, &name, NULL, NULL);
  
  if (name)
    type = ip2k_get_function_type_internal(name);
  else
    type = ip2k_func_type_normal;

  if (debug_level >= DEBUG_FRAME)
    {
      char *typestr;
      switch (type)
        {
	case ip2k_func_type_normal:
	  typestr = "normal";
	  break;
	case ip2k_func_type_libgcc_stub:
	  typestr = "libgcc stub";
	  break;
	case ip2k_func_type_libgcc_epilogue:
	  typestr = "libgcc epilogue";
	  break;
	case ip2k_func_type_libgcc_indcall:
	  typestr = "libgcc indcall";
	  break;
	default:
	  typestr = "internal error!";
	  break;
	}
      printf_filtered("ip2k_get_function_type: %s (%s)\n", typestr, name);
    }

  return type;
}

/* ip2k_pseudo_register_read.  */
static void
ip2k_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
			   int regnum, void *buf)
{
  unsigned char *data = (unsigned char *) buf;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_pseudo_register_read: %04x\n", regnum);

  switch (regnum)
    {
    case IP2K_PC_REGNUM:
      regcache_raw_read (regcache, IP2K_PCH_REGNUM, data++);
      regcache_raw_read (regcache, IP2K_PCL_REGNUM, data++);
      break;
    case IP2K_SP_REGNUM:
      regcache_raw_read (regcache, IP2K_SPH_REGNUM, data++);
      regcache_raw_read (regcache, IP2K_SPL_REGNUM, data++);
      break;
    case IP2K_DP_REGNUM:
      regcache_raw_read (regcache, IP2K_DPH_REGNUM, data++);
      regcache_raw_read (regcache, IP2K_DPL_REGNUM, data++);
      break;
    case IP2K_IP_REGNUM:
      regcache_raw_read (regcache, IP2K_IPH_REGNUM, data++);
      regcache_raw_read (regcache, IP2K_IPL_REGNUM, data++);
      break;
    case IP2K_CALL_REGNUM:
      regcache_raw_read (regcache, IP2K_CALLH_REGNUM, data++);
      regcache_raw_read (regcache, IP2K_CALLL_REGNUM, data++);
      break;
    default:
      warning ("internal error: ip2k_pseudo_register_read: invalid register: 0x%08x", regnum);
    }
}

/* ip2k_pseudo_register_write.  */
static void
ip2k_pseudo_register_write (struct gdbarch *gdbarch,
			    struct regcache *regcache, int regnum,
			    const void *buf)
{
  unsigned char *data = (unsigned char *) buf;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_pseudo_register_write\n");

  switch (regnum)
    {
    case IP2K_PC_REGNUM:
      regcache_raw_write (regcache, IP2K_PCH_REGNUM, data++);
      regcache_raw_write (regcache, IP2K_PCL_REGNUM, data++);
      break;
    case IP2K_SP_REGNUM:
      regcache_raw_write (regcache, IP2K_SPH_REGNUM, data++);
      regcache_raw_write (regcache, IP2K_SPL_REGNUM, data++);
      break;
    case IP2K_DP_REGNUM:
      regcache_raw_write (regcache, IP2K_DPH_REGNUM, data++);
      regcache_raw_write (regcache, IP2K_DPL_REGNUM, data++);
      break;
    case IP2K_IP_REGNUM:
      regcache_raw_write (regcache, IP2K_IPH_REGNUM, data++);
      regcache_raw_write (regcache, IP2K_IPL_REGNUM, data++);
      break;
    case IP2K_CALL_REGNUM:
      regcache_raw_write (regcache, IP2K_CALLH_REGNUM, data++);
      regcache_raw_write (regcache, IP2K_CALLL_REGNUM, data++);
      break;
    default:
      warning ("internal error: ip2k_pseudo_register_write: invalid register: 0x%08x", regnum);
    }
}

/* ip2k_extract_return_value.
   Extract from an array REGBUF containing the (raw) register state
   a function return value of type TYPE, and copy that, in virtual format,
   into VALBUF.  */
static void
ip2k_extract_return_value (struct type *type, struct regcache *regcache,
			   void *valbuf)
{
  int type_len, i;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_extract_return_value\n");

  type_len = TYPE_LENGTH (type);
  if (type_len > 8)
    {
      printf_unfiltered	("Error: Return values longer than 8 bytes are not supported.\n");
      memset (valbuf, 0, type_len);
      return;
    }

  if (type_len == 1)
    regcache_raw_read (regcache, IP2K_RETVAL_REGNUM + 1, valbuf);
  else
    {
      for (i = 0; i < type_len; i++)
	{
	  regcache_raw_read (regcache, IP2K_RETVAL_REGNUM + i,
			     ((char *) valbuf)++);
	}
    }
}

/* ip2k_store_return_value.
   Write into appropriate registers a function return value
   of type TYPE, given in virtual format. */
static void
ip2k_store_return_value (struct type *type, struct regcache *regcache,
			 const void *valbuf)
{
  int type_len, i;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_store_return_value\n");

  type_len = TYPE_LENGTH (type);
  if (type_len > 8)
    {
      printf_unfiltered ("Error: Return values longer than 8 bytes are not supported.\n");
      return;
    }

  if (type_len == 1)
    {
      unsigned char zero = 0;
      regcache_raw_write (regcache, IP2K_RETVAL_REGNUM + 0, &zero);
      regcache_raw_write (regcache, IP2K_RETVAL_REGNUM + 1, valbuf);
    }
  else
    {
      for (i = 0; i < type_len; i++)
	{
	  regcache_raw_write (regcache, IP2K_RETVAL_REGNUM + i,
			      ((char *) valbuf)++);
	}
    }
}

/* ip2k_use_struct_convention

   Return 1 if we should we use EXTRACT_STRUCT_VALUE_ADDRESS to
   extract the return value.

   Return 0 if we should use EXTRACT_RETURN_VALUE.

   GCC_P is true if compiled with GCC and TYPE is the type
   (which is known to be a struct, union, or array).

   For the ip2k, gcc is the only compiler and anything
   8 bytes or smaller in size is returned in registers.  */

static int
ip2k_use_struct_convention (int gcc_p, struct type *type)
{
  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_use_struct_convention\n");

  return (TYPE_LENGTH (type) > 8);
}

/* ip2k_extract_struct_value_address
   Extract from an array REGBUF containing the (raw) register state
   the address in which a function should return its structure value,
   as a CORE_ADDR (or an expression that can be used as one).  */
static CORE_ADDR
ip2k_extract_struct_value_address (struct regcache *regcache)
{
  CORE_ADDR sp;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_extract_struct_value_address\n");

  /* The called function has returned...

     And the place to store the structure return value was stored on
     the stack as a "hidden" first argument to the function called...

     All stack adjustments made by the called function should have been
     undone already, and the first argument should therefore be located
     at sp+1,sp+2.  */

  sp = ip2k_dptr_to_addr (read_register (IP2K_SP_REGNUM));
  return ip2k_dptr_to_addr (read_memory_unsigned_integer (sp + 1, 2));
}

/* ip2k_breakpoint_from_pc.  */
static const unsigned char *
ip2k_breakpoint_from_pc (CORE_ADDR * pc, int *len)
{
  static unsigned char break_insn[] = { 0x00, 0x01 };
  static unsigned char breakx_insn[] = { 0x00, 0x05 };
  unsigned short insn;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_breakpoint_from_pc\n");

  insn = read_memory_unsigned_integer (*pc, 2);
  if (((insn & 0xFF00) == 0x7000) ||
      ((insn & 0xFF00) == 0x7100) || ((insn & 0xFFF8) == 0x0010))
    {
      *len = sizeof (breakx_insn);
      return breakx_insn;
    }
  else
    {
      *len = sizeof (break_insn);
      return break_insn;
    }
}

/* ip2k_ignore_helper.
   Return non-zero if the PC is in a library helper function that should
   be ignored.  This implements the IGNORE_HELPER_CALL macro.  */
int
ip2k_ignore_helper (CORE_ADDR pc)
{
  enum ip2k_func_type type;

  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_ignore_helper\n");

  type = ip2k_get_function_type (pc, 0);
  switch (type)
    {
    case ip2k_func_type_libgcc_stub:
    case ip2k_func_type_libgcc_epilogue:
      return 1;
    case ip2k_func_type_normal:
    case ip2k_func_type_libgcc_indcall:
    default:
      return 0;
    }
}

/* ip2k_in_call_trampoline.  */
static int
ip2k_in_call_trampoline (CORE_ADDR pc, char *name)
{
  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_in_call_trampoline\n");

  if (ip2k_get_function_type (pc, name) == ip2k_func_type_libgcc_indcall)
    return 1;
    
  return 0;
}

/* ip2k_in_return_trampoline.  */
static int
ip2k_in_return_trampoline (CORE_ADDR pc, char *name)
{
  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_in_return_trampoline\n");

  if (ip2k_get_function_type (pc, name) == ip2k_func_type_libgcc_epilogue)
    return 1;
    
  return 0;
}

/* ip2k_skip_trampoline.  */
static CORE_ADDR
ip2k_skip_trampoline (CORE_ADDR pc)
{
  enum ip2k_func_type type;
  unsigned short insn;

  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_skip_trampoline\n");

  type = ip2k_get_function_type (pc, 0);
  if ((type != ip2k_func_type_libgcc_indcall) && (type != ip2k_func_type_libgcc_epilogue))
    return 0;

  /* If we are at a ret instruction then the destination address can be found in
     CALLH/CALLL.  */
  insn = read_memory_unsigned_integer (pc, 2);
  if (insn == 0x0007)
    return ip2k_iptr_to_addr (read_register (IP2K_CALL_REGNUM));
    
  /* We are not at a ret instuction so CALLH/CALLL may not be valid...
     search for the ret instruction and lie and say that the pc of the ret
     instruction is the way out. When it stops again it will recheck and
     discover that we are stil in the trampoline but by then CALLH/CALLL
     will be valid.  */
  while (1)
    {
      pc += 2;
      insn = read_memory_unsigned_integer (pc, 2);
      if (insn == 0x0007)
        /* Return pc of ret instruction */
        return pc;
    }
}

/* ip2k_skip_prologue.
   Analyze instructions to find the end  of the prologue, return the pc
   of the end of the prologue */
static CORE_ADDR
ip2k_skip_prologue (CORE_ADDR pc)
{
  unsigned char buf[20];
  unsigned char *pos = buf;
  CORE_ADDR start_pc;
  int length;

  if (debug_level >= DEBUG_MAX)
    printf_filtered ("ip2k_skip_prologue\n");

  /* Find entry_pc.  */
  start_pc = ip2k_try_pc_function_start (pc);

  /* Read prologue.  */
  if (target_read_memory (start_pc, buf, sizeof (buf)) != 0)
    memset (buf, 0, sizeof (buf));

  /* push CALLH/L will always be first (if present).  */
  if (memcmp (buf, ip2k_call_prologue_insns, sizeof (ip2k_call_prologue_insns)) == 0)
    {
      start_pc += sizeof (ip2k_call_prologue_insns);
      pos += sizeof (ip2k_call_prologue_insns);
    }

  /* FP code will be next (if present).  */
  if (memcmp (buf, ip2k_fp_prologue_insns, sizeof (ip2k_fp_prologue_insns)) == 0)
    {
      start_pc += sizeof (ip2k_fp_prologue_insns);
      pos += sizeof (ip2k_fp_prologue_insns);
    }

  /* Local variable code will be next (if present).  */
  if (memcmp (buf, ip2k_local_1_prologue_insns, sizeof (ip2k_local_1_prologue_insns)) == 0)
    {
      start_pc += sizeof (ip2k_local_1_prologue_insns);
      pos += sizeof (ip2k_local_1_prologue_insns);
    }
  buf[1] = 0x00;
  if (memcmp (buf, ip2k_local_n_prologue_insns, sizeof (ip2k_local_n_prologue_insns)) == 0)
    {
      start_pc += sizeof (ip2k_local_n_prologue_insns);
      pos += sizeof (ip2k_local_n_prologue_insns);
    }

  return start_pc;
}

/* ip2k_frame_unwind_cache.  */
struct ip2k_unwind_cache *
ip2k_frame_unwind_cache (struct frame_info *next_frame,
                        void **this_prologue_cache)
{
  struct ip2k_unwind_cache *info;
  CORE_ADDR return_pc, return_verify, temp_sp, addr;
  enum ip2k_func_type type;
  unsigned short insn;
  unsigned char buf[20];
  unsigned char *pos = buf;
  int local_stack = 0;
  int executed_stack = 0;
  int ret_saved = 0;
  int position, temp;

  if ((*this_prologue_cache))
    return (*this_prologue_cache);

  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_frame_unwind_cache:\n");
    
  info = FRAME_OBSTACK_ZALLOC (struct ip2k_unwind_cache);
  (*this_prologue_cache) = info;
  info->saved_regs = trad_frame_alloc_saved_regs (next_frame);

  /* Starting point.  */
  info->current_pc = frame_pc_unwind (next_frame);
  info->entry_pc = frame_func_unwind (next_frame);
  info->return_pc = 0;
  info->entry_sp = 0;
  info->normal_sp = 0;
  info->current_sp = frame_sp_unwind (next_frame);
  type = ip2k_get_function_type (info->current_pc, 0);

  /* Read prologue.  */
  position = (info->current_pc - info->entry_pc) / 2;
  if (target_read_memory (info->entry_pc, buf, sizeof (buf)) != 0)
    memset (buf, 0, sizeof (buf));

  /*	push CALLL	(0x447f)
	push CALLH	(0x447e) */
  if (memcmp (pos, ip2k_call_prologue_insns, sizeof (ip2k_call_prologue_insns)) == 0)
    {
      ret_saved = 1;
      local_stack += 2;
      if (position >= 2)
        executed_stack += 2;
      else if (position >= 1)
        executed_stack += 1;
      pos += sizeof (ip2k_call_prologue_insns);
      position -= sizeof (ip2k_call_prologue_insns) / 2;
    }

  /*	push $fe	(0x44fe)
	mov W,SPL	(0x2007)
	mov $fe,W	(0x02fe)
	mov W,SPH	(0x2006)
	push $fd	(0x44fd)
	mov $fd,W	(0x02fd) */
  if (memcmp (pos, ip2k_fp_prologue_insns, sizeof (ip2k_fp_prologue_insns)) == 0)
    {
      local_stack += 2;
      if (position >= 5)
        executed_stack += 2;
      else if (position >= 1)
        executed_stack += 1;
      pos += sizeof (ip2k_fp_prologue_insns);
      position -= sizeof (ip2k_fp_prologue_insns) / 2;
    }

  /*	mov W,#$xx	(0x7cxx)
	sub SPL,W	(0x0a07) */
  temp = pos[1];
  pos[1] = 0x00;
  if (memcmp (pos, ip2k_local_n_prologue_insns, sizeof (ip2k_local_n_prologue_insns)) == 0)
    {
      local_stack += temp;
      if (position >= 2)
        executed_stack += temp;
      pos += sizeof (ip2k_local_n_prologue_insns);
      position -= sizeof (ip2k_local_n_prologue_insns) / 2;
    }

  /* Special handling if we are in the middle of the prologue.  */
  if (position < 0)
    {
      info->return_pc = ip2k_iptr_to_addr (read_register (IP2K_CALL_REGNUM));
      info->entry_sp = info->current_sp + executed_stack;
      info->normal_sp = info->entry_sp - local_stack;
      goto finish;
    }

  /* Apply stack estimate.  */
  info->normal_sp = info->current_sp;
  info->entry_sp = info->current_sp + local_stack;
  
  /* Impossible to search for adjust if this is a leaf function.  */
  if ((ret_saved == 0) && (type != ip2k_func_type_libgcc_epilogue))
    {
      info->return_pc = ip2k_iptr_to_addr (read_register (IP2K_CALL_REGNUM));
      goto finish;
    }

  /* Check to see if we are in a critical part of an epilogue.  */
  insn = read_memory_unsigned_integer (info->current_pc, 2);
  if (insn == 0x0007)
    {
      printf_filtered ("\tepilogue (ret)\n");
      info->return_pc = ip2k_iptr_to_addr (read_register (IP2K_CALL_REGNUM));
      if (debug_level >= DEBUG_FRAME)
      goto finish;
    }
  if (insn == 0x467f)
    {
      printf_filtered ("\tepilogue (pop calll)\n");
      if (target_read_memory (info->current_sp + 1, buf, 1) != 0)
        {
          if (debug_level >= DEBUG_FRAME)
            printf_filtered ("\tnot found on stack (invalid sp in epilogue)!\n");
          goto finish;
	}
      info->return_pc = ip2k_iptr_to_addr(
      			  (read_register (IP2K_CALL_REGNUM) & 0x0000FF00)
      		          | (buf[0] & 0x0FF));
      info->entry_sp++;
      goto finish;
    }

  /* Search for frame on stack.
     Return address should be at entry_sp-2 (+1 for actual read as 1(SP)
     points to stack).  */
  temp_sp = info->entry_sp - 2;
  while (1)
    {
      /* Limit back search to 128 bytes.  */
      if (temp_sp > info->entry_sp + 128)
        {
          if (debug_level >= DEBUG_FRAME)
            printf_filtered ("\tnot found on stack (too far)!\n");
          break;
        }

      /* Read memory the manual way so that we can handle it
         nicely when it fails.  */
      if (target_read_memory (temp_sp + 1, buf, 2) != 0)
        /* reached/exceeded stack memory.  */
        {
          if (debug_level >= DEBUG_FRAME)
            printf_filtered ("\tnot found on stack (mem err)!\n");
          break;
        }

      /* Increment temp_sp now so that continues can work.  */
      temp_sp += 1;

      /* Process potential return pc value from stack.  */
      return_pc = extract_unsigned_integer (buf, 2);
      if (return_pc < 4)
        continue;
      return_pc = ip2k_iptr_to_addr (return_pc);
      if (target_read_memory (return_pc - 4, buf, 4) != 0)
        continue;

      /* Verify instruction at return_pc is a call instruction.  */
      insn = extract_unsigned_integer (buf + 2, 2);
      if ((insn & 0xE000) != 0xC000)
        continue;

      /* Found a possible call instruction.  */
      return_verify = insn & 0x1FFF;
      insn = extract_unsigned_integer (buf + 0, 2);
      if ((insn & 0xFFF8) == 0x0010)
        return_verify |= (insn << 13) & 0x0E000;
      else
        return_verify |= ip2k_addr_to_iptr(return_pc) & 0x0E000;
      return_verify = ip2k_iptr_to_addr(return_verify);
		  
      /* Verify that this is the expected call instruction.  */
      if ((return_verify != info->entry_pc)
        && (type != ip2k_func_type_libgcc_epilogue)
        && (ip2k_get_function_type (return_verify, 0) != ip2k_func_type_libgcc_indcall))
        continue;

      /* Found!  */
      info->return_pc = return_pc;

      /* Apply stack adjust.  */
      temp_sp += 2 - 1;
      if (temp_sp != info->entry_sp)
        {
          if (debug_level >= DEBUG_FRAME)
            printf_filtered ("\tcorrection of %ld applied\n", temp_sp - info->entry_sp);
          info->normal_sp += (temp_sp - info->entry_sp);
          info->entry_sp = temp_sp;
        }
      else
        {
          if (debug_level >= DEBUG_FRAME)
            printf_filtered ("\tno correction needed\n");
        }
      break;
    }

finish:
  
  if (info->return_pc == 0)
    info->entry_sp = 0;

  addr = ip2k_addr_to_dptr(info->entry_sp);
  trad_frame_register_value (info->saved_regs, IP2K_SP_REGNUM, addr);
  trad_frame_register_value (info->saved_regs, IP2K_SPH_REGNUM, addr >> 8);
  trad_frame_register_value (info->saved_regs, IP2K_SPL_REGNUM, addr & 0x0FF);

  addr = ip2k_addr_to_iptr(info->return_pc);
  trad_frame_register_value (info->saved_regs, IP2K_PC_REGNUM, addr);
  trad_frame_register_value (info->saved_regs, IP2K_PCH_REGNUM, addr >> 8);
  trad_frame_register_value (info->saved_regs, IP2K_PCL_REGNUM, addr & 0x0FF);

  if (debug_level >= DEBUG_FRAME)
    {
      printf_filtered ("\tentry_pc = 0x%08lx\n", info->entry_pc);
      printf_filtered ("\tcurrent_pc = 0x%08lx\n", info->current_pc);
      printf_filtered ("\treturn_pc = 0x%08lx\n", info->return_pc);
      printf_filtered ("\tentry_sp = 0x%08lx\n", info->entry_sp);
      printf_filtered ("\tnormal_sp = 0x%08lx\n", info->normal_sp);
      printf_filtered ("\tcurrent_sp = 0x%08lx\n", info->current_sp);
    }

  return info;
}

/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
   dummy frame.  The frame ID's base needs to match the TOS value
   saved by save_dummy_frame_tos(), and the PC match the dummy frame's
   breakpoint.  */
static struct frame_id
ip2k_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
  ULONGEST base;

  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_unwind_dummy_id\n");

  frame_unwind_unsigned_register (next_frame, IP2K_SP_REGNUM, &base);
  return frame_id_build (ip2k_dptr_to_addr(base), frame_pc_unwind (next_frame));
}

/* Given a GDB frame, determine the address of the calling function's
   frame.  This will be used to create a new GDB frame struct.  */
static void
ip2k_frame_this_id (struct frame_info *next_frame,
		    void **this_prologue_cache,
		    struct frame_id *this_id)
{
  struct ip2k_unwind_cache *info;
  CORE_ADDR base;
  CORE_ADDR func;
  struct frame_id id;

  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_frame_this_id\n");

  info = ip2k_frame_unwind_cache (next_frame, this_prologue_cache);

  /* The FUNC is easy.  */
  func = frame_func_unwind (next_frame);

  /* This is meant to halt the backtrace at "_start".  Make sure we
     don't halt it at a generic dummy frame. */
  if (inside_entry_file (func))
    return;

  base = info->normal_sp;
  if (base == 0)
    return;

  id = frame_id_build (base, func);

  /* Check that we're not going round in circles with the same frame
     ID (but avoid applying the test to sentinel frames which do go
     round in circles).  Can't use frame_id_eq() as that doesn't yet
     compare the frame's PC value.  */
  if (frame_relative_level (next_frame) >= 0
      && get_frame_type (next_frame) != DUMMY_FRAME
      && frame_id_eq (get_frame_id (next_frame), id))
    {
      if (debug_level >= DEBUG_FRAME)
        printf_filtered ("ip2k_frame_this_id: circular\n");
      return;
    }

  (*this_id) = id;
}

static void
ip2k_frame_prev_register (struct frame_info *next_frame,
			  void **this_prologue_cache,
			  int regnum, int *optimizedp,
			  enum lval_type *lvalp, CORE_ADDR *addrp,
			  int *realnump, void *bufferp)
{
  struct ip2k_unwind_cache *info
    = ip2k_frame_unwind_cache (next_frame, this_prologue_cache);
  trad_frame_prev_register (next_frame, info->saved_regs, regnum,
			    optimizedp, lvalp, addrp, realnump, bufferp);
}

static CORE_ADDR
ip2k_frame_base_address (struct frame_info *next_frame, void **this_cache)
{
  struct ip2k_unwind_cache *info;

  if (debug_level >= DEBUG_FRAME)
    printf_filtered ("ip2k_frame_base_address\n");

  info = ip2k_frame_unwind_cache (next_frame, this_cache);
  /* Note that gcc provides all debug information relative to the
     post-locals SP, not the entry_sp!  */
  return info->normal_sp;
}

static const struct frame_unwind ip2k_frame_unwind = {
  NORMAL_FRAME,
  ip2k_frame_this_id,
  ip2k_frame_prev_register
};

static const struct frame_base ip2k_frame_base = {
  &ip2k_frame_unwind,
  ip2k_frame_base_address,
  ip2k_frame_base_address,
  ip2k_frame_base_address
};

static const struct frame_unwind *
ip2k_frame_p (CORE_ADDR pc)
{
  return &ip2k_frame_unwind;
}

/* ip2k_gdbarch_init.  */
static struct gdbarch *
ip2k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
  struct gdbarch *gdbarch;

  /* Find a candidate among the list of pre-declared architectures.  */
  arches = gdbarch_list_lookup_by_info (arches, &info);
  if (arches != NULL)
    return (arches->gdbarch);

  /* No architecture found, create one.  */
  gdbarch = gdbarch_alloc (&info, 0);

  /* Integer types.  */
  set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
  set_gdbarch_int_bit (gdbarch, 2 * TARGET_CHAR_BIT);
  set_gdbarch_long_bit (gdbarch, 4 * TARGET_CHAR_BIT);
  set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);

  /* Floating point types (not supported).  */
  set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
  set_gdbarch_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
  set_gdbarch_long_double_bit (gdbarch, 4 * TARGET_CHAR_BIT);
  set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
  set_gdbarch_double_format (gdbarch, &floatformat_ieee_single_little);
  set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_single_little);

  /* Pointers types - pointers on target are 16-bits but addresses in GDB are 32-bits.  */
  set_gdbarch_ptr_bit (gdbarch, 2 * TARGET_CHAR_BIT);
  set_gdbarch_addr_bit (gdbarch, 32);
  set_gdbarch_address_to_pointer (gdbarch, ip2k_address_to_pointer);
  set_gdbarch_pointer_to_address (gdbarch, ip2k_pointer_to_address);

  /* Core register functions.  */
  set_gdbarch_read_pc (gdbarch, ip2k_read_pc);
  set_gdbarch_write_pc (gdbarch, ip2k_write_pc);
  set_gdbarch_unwind_pc (gdbarch, ip2k_unwind_pc);
  set_gdbarch_unwind_sp (gdbarch, ip2k_unwind_sp);

  /* General register functions.  */
  set_gdbarch_num_regs (gdbarch, IP2K_NUM_NATIVE_REGS);
  set_gdbarch_num_pseudo_regs (gdbarch, IP2K_NUM_PSEUDO_REGS);
  set_gdbarch_register_name (gdbarch, ip2k_register_name);
  set_gdbarch_register_type (gdbarch, ip2k_register_type);
  set_gdbarch_pseudo_register_read (gdbarch, ip2k_pseudo_register_read);
  set_gdbarch_pseudo_register_write (gdbarch, ip2k_pseudo_register_write);

  /* C data.  */
  set_gdbarch_extract_return_value (gdbarch, ip2k_extract_return_value);
  set_gdbarch_store_return_value (gdbarch, ip2k_store_return_value);
  set_gdbarch_use_struct_convention (gdbarch, ip2k_use_struct_convention);
  set_gdbarch_extract_struct_value_address (gdbarch,
					    ip2k_extract_struct_value_address);

  /* Code.  */
  set_gdbarch_print_insn (gdbarch, print_insn_ip2k);
  set_gdbarch_call_dummy_address (gdbarch, entry_point_address);
//  set_gdbarch_push_dummy_call (gdbarch, ip2k_push_dummy_call);

  set_gdbarch_decr_pc_after_break (gdbarch, 0);
  set_gdbarch_function_start_offset (gdbarch, 0);
  set_gdbarch_breakpoint_from_pc (gdbarch, ip2k_breakpoint_from_pc);

  set_gdbarch_in_solib_call_trampoline (gdbarch, ip2k_in_call_trampoline);
  set_gdbarch_in_solib_return_trampoline (gdbarch, ip2k_in_return_trampoline);
  set_gdbarch_skip_trampoline_code (gdbarch, ip2k_skip_trampoline);
  set_gdbarch_skip_prologue (gdbarch, ip2k_skip_prologue);
  set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
  set_gdbarch_frame_args_skip (gdbarch, 0);
  set_gdbarch_frameless_function_invocation (gdbarch,
					     frameless_look_for_prologue);

  set_gdbarch_unwind_dummy_id (gdbarch, ip2k_unwind_dummy_id);
  frame_unwind_append_predicate (gdbarch, ip2k_frame_p);
  frame_base_set_default (gdbarch, &ip2k_frame_base);

  set_gdbarch_print_insn (gdbarch, print_insn_ip2k);

  /* Complete.  */
  return (gdbarch);
}

/* _initialize_ip2k_tdep.  */
void
_initialize_ip2k_tdep (void)
{
  register_gdbarch_init (bfd_arch_ip2k, ip2k_gdbarch_init);
}

[-- Attachment #3: tm-ip2k.h --]
[-- Type: application/octet-stream, Size: 1280 bytes --]

/* Target-specific definition for the Ubicom IP2K
   Copyright (C) 2000, 2001 Free Software Foundation, Inc.

   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 2 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, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.  */

#ifndef TM_IP2K_H
#define TM_IP2K_H

#ifndef GDB_MULTI_ARCH
#define GDB_MULTI_ARCH 1
#endif

/* Define the bit, byte, and word ordering of the machine. */
#define TARGET_BYTE_ORDER	BFD_ENDIAN_BIG

/* Functions for dealing with epilogue call and return stubs. */
#define IGNORE_HELPER_CALL(pc) ip2k_ignore_helper (pc)
extern int ip2k_ignore_helper (CORE_ADDR pc);

#endif /* TM_IP2K_H */

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

* Re: ip2k port
  2003-09-15 19:39 ip2k port Jafa
@ 2003-09-22  6:46 ` Andrew Cagney
  0 siblings, 0 replies; 2+ messages in thread
From: Andrew Cagney @ 2003-09-22  6:46 UTC (permalink / raw)
  To: Jafa; +Cc: gdb

This isn't needed.  All targets a bi-endian.  Even the i386:

> /* Define the bit, byte, and word ordering of the machine. */
> #define TARGET_BYTE_ORDER       BFD_ENDIAN_BIG

Ok, looks like this will need multi-arching. Can you file a bug report 
to track this?

> /* Functions for dealing with epilogue call and return stubs. */
> #define IGNORE_HELPER_CALL(pc) ip2k_ignore_helper (pc)
> extern int ip2k_ignore_helper (CORE_ADDR pc);

This thread stuff could do with some comments, I'm also wondering if 
these constants belong in a header somewhere:

/* Threads.  */
#define IP2K_ISR_THREAD 1
#define IP2K_MAIN_THREAD 2
#define IP2K_VM_THREAD 3

Where sensible, use enums, rather than #define's:

#define DEBUG_NONE 0
#define DEBUG_NORMAL 1
#define DEBUG_EXTRA 2
#define DEBUG_MAX 3

Use NOINDENT (Ref: defs.h), otherwize, gdb_indent.sh will muck up these 
tables:

/* Prologue instructions - return address.
         push CALLL      (0x447f)
         push CALLH      (0x447e) */

Debug output is printed with "fprintf_unfiltered (gdb_stdlog, ...):
  if (debug_level >= DEBUG_MAX)
     printf_filtered ("ip2k_address_to_pointer\n");

Print CORE_ADDRS using "0x%s", paddr[_nz]():

       warning ("invalid instruction pointer: 0x%08lx", addr);

Don't print internal errors using warning, call internal_error, or even 
just use ARRAY_SIZE in an assert:

       warning ("internal error: ip2k_register_name: invalid register: 
0x%08x", r

Use warning(), not printf_filtered for warnings:

   printf_filtered ("warning: unable to find start of function of pc: 
0x%08lx\n",
  pc);

Call error() for errors:

       printf_unfiltered ("Error: Return values longer than 8 bytes are 
not suppo
rted.\n");

If you re-factor the function (spliting it into two), the "goto" can be 
replaced by a "return:

	finish:

I've fixed frame.c, so this is no longer needed:

   /* Check that we're not going round in circles with the same frame
      ID (but avoid applying the test to sentinel frames which do go
      round in circles).  Can't use frame_id_eq() as that doesn't yet
      compare the frame's PC value.  */

In the frame code, frame*memory, instead of target_read_memory, should 
be used:

       if (target_read_memory (info->current_sp + 1, buf, 1) != 0)

	finish:

It all looks byte order clean (which is the most common problem) and not 
to scary.  The above are all minor tweaks.

BTW, do you have a list of people that contributed to the file?

Andrew

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

end of thread, other threads:[~2003-09-22  6:46 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-09-15 19:39 ip2k port Jafa
2003-09-22  6:46 ` Andrew Cagney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).