* [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
@ 2012-05-11 16:09 Jeff Kenton
2012-05-14 16:21 ` Joel Brobecker
2012-05-14 16:24 ` Joel Brobecker
0 siblings, 2 replies; 16+ messages in thread
From: Jeff Kenton @ 2012-05-11 16:09 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 651 bytes --]
This is a re-submission of the port of GDB to the Tilera TILE-Gx
processor, re-organized and modified in response to multiple suggestions
from several people.
This is part 1 of 3, containing basic support for the TILE-Gx
processor. Patch is attached. It contains:
gdb/
* tilegx-linux-tdep.c: New file
* tilegx-tdep.c: New file
* configure.host: Add tilegx target.
* configure.tgt: Add tilegx target.
* Makefile.in: Add tilegx dependencies.
gdb/regformats/
* reg-tilegx.dat: New file.
gdb/config/tilegx/
* nm-linux.h: New file.
Comments please.
Thanks.
jeff kenton (jkenton@tilera.com)
[-- Attachment #2: patch_1 --]
[-- Type: text/plain, Size: 47772 bytes --]
# The actual Tilera patch starts here.
diff -r -u -N /home/packages/gdb-7.4x/gdb/config/tilegx/nm-linux.h ./gdb/config/tilegx/nm-linux.h
--- /home/packages/gdb-7.4x/gdb/config/tilegx/nm-linux.h 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/config/tilegx/nm-linux.h 2012-05-08 10:38:23.722537000 -0400
@@ -0,0 +1,27 @@
+/* Native-dependent definitions for GNU/Linux on TILE.
+
+ Copyright (C) 2012 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 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/>. */
+
+#ifndef NM_TILELINUX_H
+#define NM_TILELINUX_H
+
+#undef HAVE_LINK_H
+
+#include "config/nm-linux.h"
+
+#endif /* NM_TILELINUX_H */
diff -r -u -N /home/packages/gdb-7.4x/gdb/configure.host ./gdb/configure.host
--- /home/packages/gdb-7.4x/gdb/configure.host 2011-05-04 15:28:14.000000000 -0400
+++ ./gdb/configure.host 2012-05-08 10:38:23.748524000 -0400
@@ -50,6 +50,7 @@
sparcv9 | sparc64) gdb_host_cpu=sparc ;;
s390*) gdb_host_cpu=s390 ;;
sh*) gdb_host_cpu=sh ;;
+tilegx*) gdb_host_cpu=tilegx ;;
x86_64*) gdb_host_cpu=i386 ;;
m32r*) gdb_host_cpu=m32r ;;
xtensa*) gdb_host_cpu=xtensa ;;
@@ -159,6 +160,8 @@
gdb_host=sol2
;;
+tilegx-*-*) gdb_host=tilegx ;;
+
vax-*-bsd*) gdb_host=vax ;;
vax-*-netbsdelf* | vax-*-knetbsd*-gnu)
gdb_host=nbsdelf ;;
diff -r -u -N /home/packages/gdb-7.4x/gdb/configure.tgt ./gdb/configure.tgt
--- /home/packages/gdb-7.4x/gdb/configure.tgt 2012-03-05 06:41:51.000000000 -0500
+++ ./gdb/configure.tgt 2012-05-08 10:38:23.761527000 -0400
@@ -551,6 +551,13 @@
gdb_target_obs="tic6x-tdep.o"
;;
+tilegx-*-linux*)
+ # Target: TILE-Gx
+ gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
+ symfile-mem.o glibc-tdep.o linux-tdep.o"
+ build_gdbserver=yes
+ ;;
+
xstormy16-*-*)
# Target: Sanyo Xstormy16a processor
gdb_target_obs="xstormy16-tdep.o"
diff -r -u -N /home/packages/gdb-7.4x/gdb/Makefile.in ./gdb/Makefile.in
--- /home/packages/gdb-7.4x/gdb/Makefile.in 2012-03-28 17:31:18.000000000 -0400
+++ ./gdb/Makefile.in 2012-05-08 10:38:23.700553000 -0400
@@ -565,6 +565,7 @@
sparc-sol2-tdep.o sparc-tdep.o \
spu-tdep.o spu-multiarch.o solib-spu.o \
tic6x-tdep.o tic6x-linux-tdep.o \
+ tilegx-tdep.o tilegx-linux-tdep.o \
v850-tdep.o \
vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
xstormy16-tdep.o \
@@ -1510,6 +1511,7 @@
sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
+ tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c \
v850-tdep.c \
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
windows-nat.c windows-tdep.c \
diff -r -u -N /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat ./gdb/regformats/reg-tilegx.dat
--- /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/regformats/reg-tilegx.dat 2012-05-08 10:38:23.832533000 -0400
@@ -0,0 +1,67 @@
+name:tile
+expedite:sp,lr,pc
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:r32
+64:r33
+64:r34
+64:r35
+64:r36
+64:r37
+64:r38
+64:r39
+64:r40
+64:r41
+64:r42
+64:r43
+64:r44
+64:r45
+64:r46
+64:r47
+64:r48
+64:r49
+64:r50
+64:r51
+64:r52
+64:tp
+64:sp
+64:lr
+64:sn
+64:io0
+64:io1
+64:us0
+64:us1
+64:us2
+64:us3
+64:zero
+64:pc
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-linux-tdep.c 2012-05-10 08:49:18.524447000 -0400
@@ -0,0 +1,116 @@
+/* Target-dependent code for GNU/Linux on Xtensa processors.
+
+ Copyright 2012 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 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 "osabi.h"
+#include "linux-tdep.h"
+#include "glibc-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "tramp-frame.h"
+
+/* Signal trampoline support. */
+
+static void
+tilegx_linux_sigframe_init (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ /* Stub. */
+}
+
+
+static const struct tramp_frame tilegx_linux_rt_sigframe =
+{
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
+ { 0x286b180051485000, -1 }, /* { swint1 } */
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ tilegx_linux_sigframe_init
+};
+
+/* OS specific initialization of gdbarch. */
+
+static void
+tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ linux_init_abi (info, gdbarch);
+
+ tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
+
+ /* Shared library handling. */
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_linux_tdep;
+
+void
+_initialize_tilegx_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_tilegx, bfd_mach_tilegx, GDB_OSABI_LINUX,
+ tilegx_linux_init_abi);
+}
+
+#if 0
+/* Target-dependent code for GNU/Linux SPARC.
+
+ Copyright (C) 2003-2005, 2007-2012 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 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 "dwarf2-frame.h"
+#include "frame.h"
+#include "frame-unwind.h"
+#include "gdbtypes.h"
+#include "regset.h"
+#include "gdbarch.h"
+#include "gdbcore.h"
+#include "osabi.h"
+#include "regcache.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "trad-frame.h"
+#include "tramp-frame.h"
+#include "xml-syscall.h"
+#include "linux-tdep.h"
+
+#endif
+
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.c 2012-05-08 10:38:23.817526000 -0400
@@ -0,0 +1,1147 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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 "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "dis-asm.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "regset.h"
+#include "doublest.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "objfiles.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+
+#include "opcode/tilegx.h"
+
+/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
+ * plus 8 special general purpose registers (network and ZERO),
+ * plus 1 magic register (PC).
+ *
+ * TP (aka R53) is the thread specific data pointer.
+ * SP (aka R54) is the stack pointer.
+ * LR (aka R55) is the link register.
+ */
+enum {
+
+ E_R0_REGNUM,
+ E_R1_REGNUM,
+ E_R2_REGNUM,
+ E_R3_REGNUM,
+ E_R4_REGNUM,
+ E_R5_REGNUM,
+ E_R6_REGNUM,
+ E_R7_REGNUM,
+ E_R8_REGNUM,
+ E_R9_REGNUM,
+ E_R10_REGNUM,
+ E_R11_REGNUM,
+ E_R12_REGNUM,
+ E_R13_REGNUM,
+ E_R14_REGNUM,
+ E_R15_REGNUM,
+ E_R16_REGNUM,
+ E_R17_REGNUM,
+ E_R18_REGNUM,
+ E_R19_REGNUM,
+ E_R20_REGNUM,
+ E_R21_REGNUM,
+ E_R22_REGNUM,
+ E_R23_REGNUM,
+ E_R24_REGNUM,
+ E_R25_REGNUM,
+ E_R26_REGNUM,
+ E_R27_REGNUM,
+ E_R28_REGNUM,
+ E_R29_REGNUM,
+ E_R30_REGNUM,
+ E_R31_REGNUM,
+ E_R32_REGNUM,
+ E_R33_REGNUM,
+ E_R34_REGNUM,
+ E_R35_REGNUM,
+ E_R36_REGNUM,
+ E_R37_REGNUM,
+ E_R38_REGNUM,
+ E_R39_REGNUM,
+ E_R40_REGNUM,
+ E_R41_REGNUM,
+ E_R42_REGNUM,
+ E_R43_REGNUM,
+ E_R44_REGNUM,
+ E_R45_REGNUM,
+ E_R46_REGNUM,
+ E_R47_REGNUM,
+ E_R48_REGNUM,
+ E_R49_REGNUM,
+ E_R50_REGNUM,
+ E_R51_REGNUM,
+ E_R52_REGNUM,
+ E_TP_REGNUM,
+ E_SP_REGNUM,
+ E_LR_REGNUM,
+
+ E_SN_REGNUM, E_NUM_EASY_REGS = E_SN_REGNUM, /* 56 */
+ E_IO0_REGNUM,
+ E_IO1_REGNUM,
+ E_US0_REGNUM,
+ E_US1_REGNUM,
+ E_US2_REGNUM,
+ E_US3_REGNUM,
+ E_ZERO_REGNUM,
+
+ E_PC_REGNUM, E_NUM_PHYS_REGS = E_PC_REGNUM, /* 64 */
+
+ E_NUM_REGS /* 65 */
+};
+
+
+struct tilegx_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR start_pc;
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+enum reverse_state {
+ REVERSE_STATE_REGISTER,
+ REVERSE_STATE_VALUE,
+ REVERSE_STATE_UNKNOWN
+};
+
+struct tilegx_reverse_regs
+{
+ LONGEST value;
+ enum reverse_state state;
+};
+
+static const struct tilegx_reverse_regs
+template_reverse_regs[E_NUM_PHYS_REGS] =
+ {
+ { E_R0_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R1_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R2_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R3_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R4_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R5_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R6_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R7_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R8_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R9_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R10_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R11_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R12_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R13_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R14_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R15_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R16_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R17_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R18_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R19_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R20_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R21_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R22_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R23_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R24_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R25_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R26_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R27_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R28_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R29_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R30_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R31_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R32_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R33_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R34_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R35_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R36_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R37_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R38_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R39_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R40_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R41_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R42_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R43_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R44_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R45_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R46_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R47_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R48_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R49_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R50_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R51_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R52_REGNUM, REVERSE_STATE_REGISTER },
+ { E_TP_REGNUM, REVERSE_STATE_REGISTER },
+ { E_SP_REGNUM, REVERSE_STATE_REGISTER },
+ { E_LR_REGNUM, REVERSE_STATE_REGISTER },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { E_ZERO_REGNUM, REVERSE_STATE_VALUE }
+ };
+
+
+enum { tilegx_reg_size = 8 };
+
+/* This is the implementation of gdbarch method register_name. */
+
+static const char *
+tilegx_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ static const char *const register_names[E_NUM_REGS] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr",
+ "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero",
+ "pc"
+ };
+
+ if (regnum < 0 || regnum >= E_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "tilegx_register_name: illegal register number %d",
+ regnum);
+
+ return register_names[regnum];
+}
+
+/* This is the implementation of gdbarch method register_type. */
+
+static struct type *
+tilegx_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == E_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+}
+
+static int
+tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ return num;
+}
+
+
+/* Makes the decision if a given type is a scalar type. Scalar
+ types are returned in the registers r2-r11 as they fit. */
+
+static int
+tilegx_type_is_scalar (struct type *t)
+{
+ return (TYPE_CODE(t) != TYPE_CODE_STRUCT
+ && TYPE_CODE(t) != TYPE_CODE_UNION
+ && TYPE_CODE(t) != TYPE_CODE_ARRAY);
+}
+
+/* Returns non-zero if the given struct type will be returned using
+ a special convention, rather than the normal function return method.
+ Used in the context of the "return" command, and target function
+ calls from the debugger. */
+
+static int
+tilegx_use_struct_convention (struct type *type)
+{
+ /* Only scalars which fit in R0 - R9 can be returned in registers.
+ Otherwise, they are returned via a pointer passed in R0. */
+ return !tilegx_type_is_scalar (type)
+ && (TYPE_LENGTH (type) > (1 + E_R9_REGNUM - E_R0_REGNUM) * tilegx_reg_size);
+}
+
+/* Find a function's return value in the appropriate registers (in
+ regbuf), and copy it into valbuf. */
+
+static void
+tilegx_extract_return_value (struct type *type, struct regcache *regcache,
+ void *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ int i, regnum = E_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
+}
+
+/* Copy the function return value from VALBUF into the
+ proper location for a function return.
+ Called only in the context of the "return" command. */
+
+static void
+tilegx_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ if (TYPE_LENGTH (type) < tilegx_reg_size)
+ {
+ /* Add leading zeros to the value. */
+ char buf[tilegx_reg_size];
+
+ memset (buf, 0, tilegx_reg_size);
+ memcpy (buf, valbuf, TYPE_LENGTH (type));
+ regcache_raw_write (regcache, E_R0_REGNUM, buf);
+ }
+ else
+ {
+ int len = TYPE_LENGTH (type);
+ int i, regnum = E_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_write (regcache, regnum++, (char *) valbuf + i);
+ }
+}
+
+
+static enum return_value_convention
+tilegx_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (tilegx_use_struct_convention (type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ if (writebuf)
+ tilegx_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ tilegx_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+static CORE_ADDR
+tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return addr & -8;
+}
+
+
+/* Setup the function arguments for GDB to call a function in the inferior.
+ Called only in the context of a target function call from the debugger.
+ Returns the value of the SP register after the args are pushed. */
+
+static CORE_ADDR
+tilegx_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);
+ CORE_ADDR stack_dest = sp;
+ int argreg = E_R0_REGNUM;
+ int i, j;
+ int typelen, slacklen, alignlen;
+ static const int zero_words[2] = { 0, 0 };
+
+ /* If struct_return is 1, then the struct return address will
+ consume one argument-passing register. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
+
+ /* Arguments are passed in R0 - R9, and as soon as an argument will not
+ fit completely in the remaining registers, then it, and all remaining
+ arguments, are put on the stack. */
+ for (i = 0; i < nargs && argreg <= E_R9_REGNUM; i++)
+ {
+ const char *val;
+ typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
+
+ if (typelen > (E_R9_REGNUM - argreg + 1) * tilegx_reg_size)
+ break;
+
+ /* Put argument into registers wordwise. */
+ val = value_contents (args[i]);
+ for (j = 0; j < typelen; j += tilegx_reg_size)
+ {
+ /* ISSUE: Why special handling (only) for "typelen = 4x + 1"?
+ I am unable to induce any "typelen" values except 4 and 8. */
+ int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
+ ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
+ regcache_cooked_write_unsigned (regcache, argreg++, w);
+ }
+ }
+
+ /* Align SP. */
+ stack_dest = tilegx_frame_align (gdbarch, stack_dest);
+
+ /* Loop backwards through arguments to determine stack alignment. */
+ alignlen = 0;
+
+ for (j = nargs - 1; j >= i; j--)
+ {
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ alignlen += (typelen + 3) & (~3);
+ }
+
+ if (alignlen & 0x4)
+ stack_dest -= 4;
+
+ /* Loop backwards through remaining arguments and push them on the stack,
+ wordaligned. */
+ for (j = nargs - 1; j >= i; j--)
+ {
+ char *val;
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ slacklen = ((typelen + 3) & (~3)) - typelen;
+ val = alloca (typelen + slacklen);
+ memcpy (val, value_contents (args[j]), typelen);
+ memset (val + typelen, 0, slacklen);
+
+ /* Now write this data to the stack. The stack grows downwards. */
+ stack_dest -= typelen + slacklen;
+ write_memory (stack_dest, val, typelen + slacklen);
+ }
+
+ /* Add 2 words for linkage space to the stack. */
+ stack_dest = stack_dest - 8;
+ write_memory (stack_dest, (void*)zero_words, 8);
+
+ /* Update stack pointer. */
+ regcache_cooked_write_unsigned (regcache, E_SP_REGNUM, stack_dest);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_unsigned (regcache, E_LR_REGNUM, bp_addr);
+
+ return stack_dest;
+}
+
+
+/* Decode the instructions within the given address range.
+ Decide when we must have reached the end of the function prologue.
+ If a frame_info pointer is provided, fill in its saved_regs etc.
+ Returns the address of the first instruction after the prologue.
+ NOTE: This is often called with start_addr being the start of some
+ function, and end_addr being the current PC. */
+
+static CORE_ADDR
+tilegx_analyze_prologue (struct gdbarch* gdbarch,
+ CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct tilegx_frame_cache *cache,
+ struct frame_info *next_frame)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR next_addr;
+ CORE_ADDR prolog_end = end_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+ gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
+ CORE_ADDR instbuf_start;
+ unsigned int instbuf_size;
+ int status;
+ bfd_uint64_t bundle;
+ struct tilegx_decoded_instruction decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int num_insns;
+ struct tilegx_reverse_regs reverse_frame[E_NUM_PHYS_REGS];
+ struct tilegx_reverse_regs new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int reverse_frame_valid, prolog_done, branch_seen;
+ LONGEST prev_sp_value;
+ int i, j;
+
+ if (start_addr >= end_addr
+ || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
+ return end_addr;
+
+ /* Initialize the reverse frame. This maps the CURRENT frame's registers
+ to the outer frame's registers (the frame on the stack goes the other
+ way). */
+ memcpy (&reverse_frame, &template_reverse_regs, sizeof (reverse_frame));
+
+ prolog_done = 0;
+ branch_seen = 0;
+ prev_sp_value = 0;
+
+ /* To cut down on round-trip overhead, we fetch multiple bundles at once.
+ * These variables describe the range of memory we have prefetched. */
+ instbuf_start = 0;
+ instbuf_size = 0;
+
+ for (next_addr = start_addr; next_addr < end_addr;
+ next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
+ {
+ /* Retrieve the next instruction. */
+ if (next_addr - instbuf_start >= instbuf_size)
+ {
+ /* Figure out how many bytes to fetch. Don't span a page boundary
+ since that might cause an unnecessary memory error. */
+ unsigned int size_on_same_page = 4096 - (next_addr & 4095);
+ instbuf_size = sizeof instbuf;
+ if (instbuf_size > size_on_same_page)
+ instbuf_size = size_on_same_page;
+ instbuf_start = next_addr;
+
+ status = safe_frame_unwind_memory (next_frame, instbuf_start, instbuf,
+ instbuf_size);
+ if (status == 0)
+ memory_error (status, next_addr);
+ }
+
+ reverse_frame_valid = 0;
+
+ bundle = extract_unsigned_integer (&instbuf[next_addr - instbuf_start],
+ 8, byte_order);
+
+ num_insns = parse_insn_tilegx (bundle, next_addr, decoded);
+
+ for (i = 0; i < num_insns; i++)
+ {
+ struct tilegx_decoded_instruction *this_insn = &decoded[i];
+ int64_t *operands = (int64_t *)this_insn->operand_values;
+ const struct tilegx_opcode *opcode = this_insn->opcode;
+ switch (opcode->mnemonic)
+ {
+ case TILEGX_OPC_ST:
+ if (cache &&
+ reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER)
+ {
+ LONGEST saved_address = reverse_frame[operands[0]].value;
+ unsigned saved_register = (unsigned)reverse_frame[operands[1]].value;
+ /* realreg >= 0 and addr != -1 indicates that the value
+ of saved_register is in memory location saved_address.
+ The value of realreg is not meaningful in this case but
+ it must be >= 0. See trad-frame.h */
+ cache->saved_regs[saved_register].realreg = saved_register;
+ cache->saved_regs[saved_register].addr = saved_address;
+ }
+ break;
+ case TILEGX_OPC_ADDI:
+ case TILEGX_OPC_ADDLI:
+ if (cache
+ && operands[0] == E_SP_REGNUM
+ && operands[1] == E_SP_REGNUM
+ && reverse_frame[operands[1]].state ==
+ REVERSE_STATE_REGISTER)
+ {
+ /* This is a special case. We're fixing up the stack frame. */
+ uint64_t hopefully_sp =
+ (unsigned)reverse_frame[operands[1]].value;
+ short op2_as_short = (short)operands[2];
+ signed char op2_as_char = (signed char)operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+ prev_sp_value = cache->saved_regs[hopefully_sp].addr - op2_as_short;
+
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value = cache->saved_regs[hopefully_sp].addr;
+ trad_frame_set_value (cache->saved_regs, hopefully_sp, prev_sp_value);
+ }
+ else
+ {
+ short op2_as_short = (short)operands[2];
+ signed char op2_as_char = (signed char)operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
+ new_reverse_frame[i].value += op2_as_short;
+ else
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ADD:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ new_reverse_frame[i].value += reverse_frame[operands[i]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVE:
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVEI:
+ case TILEGX_OPC_MOVELI:
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value = operands[1];
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ORI:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have a value in A -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value =
+ reverse_frame[operands[1]].value | operands[2];
+ }
+ else if (operands[2] == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_OR:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ }
+ else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_SUB:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value -= reverse_frame[operands[2]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+
+ case TILEGX_OPC_FNOP:
+ case TILEGX_OPC_INFO:
+ case TILEGX_OPC_INFOL:
+ /* Nothing to see here, move on.
+ * Note that real NOP is treated as a 'real' instruction
+ * because someone must have intended that it be there.
+ * It therefore terminates the prolog.
+ */
+ break;
+
+ case TILEGX_OPC_J:
+ case TILEGX_OPC_JAL:
+
+ case TILEGX_OPC_BEQZ:
+ case TILEGX_OPC_BEQZT:
+ case TILEGX_OPC_BGEZ:
+ case TILEGX_OPC_BGEZT:
+ case TILEGX_OPC_BGTZ:
+ case TILEGX_OPC_BGTZT:
+ case TILEGX_OPC_BLBC:
+ case TILEGX_OPC_BLBCT:
+ case TILEGX_OPC_BLBS:
+ case TILEGX_OPC_BLBST:
+ case TILEGX_OPC_BLEZ:
+ case TILEGX_OPC_BLEZT:
+ case TILEGX_OPC_BLTZ:
+ case TILEGX_OPC_BLTZT:
+ case TILEGX_OPC_BNEZ:
+ case TILEGX_OPC_BNEZT:
+
+ case TILEGX_OPC_IRET:
+ case TILEGX_OPC_JALR:
+ case TILEGX_OPC_JALRP:
+ case TILEGX_OPC_JR:
+ case TILEGX_OPC_JRP:
+ case TILEGX_OPC_SWINT0:
+ case TILEGX_OPC_SWINT1:
+ case TILEGX_OPC_SWINT2:
+ case TILEGX_OPC_SWINT3:
+ /* we're really done -- this is a branch */
+ branch_seen = 1;
+ prolog_done = 1;
+ break;
+ default:
+ /* We don't know or care what this instruction is.
+ All we know is that it isn't part of a prolog, and if
+ there's a destination register, we're trashing it. */
+ prolog_done = 1;
+ for (j = 0; j < opcode->num_operands; j++)
+ {
+ if (this_insn->operands[j]->is_dest_reg)
+ {
+ dest_regs[i] = operands[j];
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ reverse_frame_valid |= 1<<i;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now update the reverse frames. */
+ for (i = 0; i < num_insns; i++)
+ {
+ /* ISSUE: Does this properly handle "network" registers? */
+ if ((reverse_frame_valid & (1<<i)) && dest_regs[i] != E_ZERO_REGNUM)
+ {
+ reverse_frame[dest_regs[i]] = new_reverse_frame[i];
+ }
+ }
+
+ if (prev_sp_value != 0)
+ {
+ /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */
+ if (reverse_frame[E_R52_REGNUM].state == REVERSE_STATE_REGISTER
+ && reverse_frame[E_R52_REGNUM].value == E_SP_REGNUM)
+ {
+ reverse_frame[E_R52_REGNUM].state = REVERSE_STATE_VALUE;
+ reverse_frame[E_R52_REGNUM].value = prev_sp_value;
+ }
+
+ prev_sp_value = 0;
+ }
+
+ if (prolog_done && prolog_end == end_addr)
+ {
+ /* We found some non-prolog code. As such, _this_ instruction is the
+ one after the prolog. We keep processing, because there may be more
+ prolog code in there, but this is what we'll return. */
+ /* ISSUE: There may not have actually been a prologue, and we may
+ have simply skipped some random instructions. */
+ prolog_end = next_addr;
+ }
+ if (branch_seen)
+ {
+ /* We saw a branch. The prolog absolutely must be over. */
+ break;
+ }
+ }
+
+ if (prolog_end == end_addr && cache)
+ {
+ /* We may have terminated the prolog early, and we're certainly at THIS
+ point right now. It's possible that the values of registers we need are
+ currently actually in other registers (and haven't been written to
+ memory yet). Go find them. */
+ for (i = 0; i < E_NUM_PHYS_REGS; i++)
+ {
+ if (reverse_frame[i].state == REVERSE_STATE_REGISTER
+ && reverse_frame[i].value != i)
+ {
+ unsigned saved_register = (unsigned)reverse_frame[i].value;
+ cache->saved_regs[saved_register].realreg = i;
+ cache->saved_regs[saved_register].addr = (LONGEST)-1;
+ }
+ }
+ }
+
+ return prolog_end;
+}
+
+/* If the input address is in a function prologue,
+ returns the address of the end of the prologue;
+ else returns the input address.
+
+ Note: the input address is likely to be the function start,
+ since this function is mainly used for advancing a breakpoint
+ to the first line, or stepping to the first line when we have
+ stepped into a function call. */
+
+static CORE_ADDR
+tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end && pc <= sal.end)
+ return sal.end;
+ }
+
+ /* Otherwise, try to skip prologue the hard way. */
+ return tilegx_analyze_prologue (gdbarch,
+ pc, pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES,
+ NULL, NULL);
+}
+
+/* The epilogue is defined here as the area at the end of a function,
+ either on the `ret' instruction itself or after an instruction which
+ destroys the function's stack frame. */
+static int
+tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0, func_end = 0;
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ ULONGEST inst, inst2;
+ CORE_ADDR addr = func_end - TILEGX_BUNDLE_SIZE_IN_BYTES;
+
+ /* FIXME: Find the actual epilogue. */
+ /* HACK: Just assume the final bundle is the "ret" instruction". */
+ if (pc > addr)
+ return 1;
+ }
+ return 0;
+}
+
+
+static const unsigned char *
+tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
+{
+ static unsigned char breakpoint[sizeof (tilegx_bundle_bits)];
+
+ tilegx_bundle_bits bits = TILEGX_BPT_BUNDLE;
+ unsigned int i;
+
+ for (i = 0; i < sizeof (breakpoint); i++)
+ {
+ breakpoint[i] = (unsigned char)bits;
+ bits >>= 8;
+ }
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+
+/* Normal frames. */
+
+static struct tilegx_frame_cache *
+tilegx_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct tilegx_frame_cache *cache;
+ CORE_ADDR current_pc;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct tilegx_frame_cache);
+ *this_cache = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+ cache->base = 0;
+ cache->start_pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+
+ cache->base = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
+ trad_frame_set_value (cache->saved_regs, E_SP_REGNUM, cache->base);
+
+ cache->saved_regs[E_PC_REGNUM] = cache->saved_regs[E_LR_REGNUM];
+
+ if (cache->start_pc)
+ tilegx_analyze_prologue (gdbarch, cache->start_pc, current_pc,
+ cache, this_frame);
+
+ return cache;
+}
+
+static struct value*
+tilegx_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int regnum)
+{
+ struct tilegx_frame_cache *info = tilegx_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum);
+}
+
+static void
+tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct tilegx_frame_cache *info = tilegx_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (info->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (info->base, info->start_pc);
+}
+
+static CORE_ADDR
+tilegx_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct tilegx_frame_cache *cache = tilegx_frame_cache (this_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_unwind tilegx_frame_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ tilegx_frame_this_id,
+ tilegx_frame_prev_register,
+ NULL, /* const struct frame_data *unwind_data */
+ default_frame_sniffer, /* frame_sniffer_ftype *sniffer */
+ NULL /* frame_prev_pc_ftype *prev_pc */
+};
+
+static const struct frame_base tilegx_frame_base = {
+ &tilegx_frame_unwind,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address
+};
+
+static CORE_ADDR
+tilegx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_SP_REGNUM);
+}
+
+static CORE_ADDR
+tilegx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_PC_REGNUM);
+}
+
+static struct frame_id
+tilegx_unwind_dummy_id (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+
+ sp = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+
+/* We cannot read/write the "special" registers. */
+
+static int
+tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno)
+{
+ if (regno >= 0 && regno < E_NUM_EASY_REGS)
+ return 0;
+ else if (regno == E_PC_REGNUM)
+ return 0;
+ else
+ return 1;
+}
+
+
+/* This logic must match that of struct pt_regs in "ptrace.h". */
+
+static void
+tilegx_linux_supply_regset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *regs, size_t len)
+{
+ struct gdbarch *arch = get_regcache_arch (regcache);
+ const char *ptr = regs;
+ int i;
+
+ for (i = 0; i < E_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size)
+ {
+ int gri = (i < E_NUM_EASY_REGS) ? i : E_PC_REGNUM;
+ if (regnum == gri || regnum == -1)
+ regcache_raw_supply (regcache, gri, ptr);
+ }
+}
+
+
+/* TILE-Gx Linux kernal register set. */
+static struct regset tilegx_linux_regset =
+{
+ NULL,
+ tilegx_linux_supply_regset
+};
+
+static const struct regset *
+tilegx_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ if (strcmp (sect_name, ".reg") == 0)
+ return &tilegx_linux_regset;
+
+ return NULL;
+}
+
+
+/* Initializer function for the tilegx gdbarch vector.
+ Called by gdbarch. Sets up the gdbarch vector(s) for this target. */
+
+static struct gdbarch *
+tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ int arch_size = 64;
+
+ /* Handle arch_size == 32 or 64. Default to 64. */
+ if (info.abfd)
+ arch_size = bfd_get_arch_size (info.abfd);
+
+ if (arch_size != 32)
+ arch_size = 64;
+
+ /* try to find a pre-existing architecture */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* We only have two flavors -- just make sure arch_size matches. */
+ if (gdbarch_ptr_bit (arches->gdbarch) == arch_size)
+ return (arches->gdbarch);
+ }
+
+ gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Basic register fields and methods, datatype sizes and stuff. */
+
+ /* There are 64 physical registers, which can be referenced by instructions
+ (although only 56 of them can actually be debugged) and 1 magic register
+ (the PC). The other three magic registers (ex1, syscall, orig_r0) which
+ are known to "ptrace" are ignored by "gdb". Note that we simply pretend
+ that there are 65 registers, and no "pseudo registers". */
+ set_gdbarch_num_regs (gdbarch, E_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+ set_gdbarch_sp_regnum (gdbarch, E_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, E_PC_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, tilegx_register_name);
+ set_gdbarch_register_type (gdbarch, tilegx_register_type);
+
+ set_gdbarch_char_signed (gdbarch, 0);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, arch_size);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_ptr_bit (gdbarch, arch_size);
+ set_gdbarch_addr_bit (gdbarch, arch_size);
+
+ set_gdbarch_cannot_fetch_register (gdbarch, tilegx_cannot_reference_register);
+ set_gdbarch_cannot_store_register (gdbarch, tilegx_cannot_reference_register);
+
+ set_gdbarch_regset_from_core_section (gdbarch,
+ tilegx_regset_from_core_section);
+
+ /* Stack grows down. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /*
+ * Frame Info
+ */
+ set_gdbarch_unwind_sp (gdbarch, tilegx_unwind_sp);
+ set_gdbarch_unwind_pc (gdbarch, tilegx_unwind_pc);
+ set_gdbarch_dummy_id (gdbarch, tilegx_unwind_dummy_id);
+ set_gdbarch_frame_align (gdbarch, tilegx_frame_align);
+ frame_base_set_default (gdbarch, &tilegx_frame_base);
+
+ set_gdbarch_skip_prologue (gdbarch, tilegx_skip_prologue);
+
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ tilegx_in_function_epilogue_p);
+
+ /* Map debug registers into internal register numbers. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, tilegx_dwarf2_reg_to_regnum);
+
+ /* These values and methods are used when gdb calls a target function. */
+ set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call);
+ set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc);
+ set_gdbarch_return_value (gdbarch, tilegx_return_value);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_tilegx);
+
+ /* GNU/Linux uses SVR4-style shared libraries. */
+ if (arch_size == 32)
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+ else
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
+
+ gdbarch_init_osabi (info, gdbarch);
+
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &tilegx_frame_unwind);
+
+ return gdbarch;
+}
+
+
+/* Initializer function for the Tilera TILE-Gx chip.
+ Called by gdb at start-up. */
+
+extern initialize_file_ftype _initialize_tilegx_tdep; /* -Wmissing-prototypes */
+
+void
+_initialize_tilegx_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
+}
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-11 16:09 [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb) Jeff Kenton
@ 2012-05-14 16:21 ` Joel Brobecker
2012-05-21 14:23 ` Jeff Kenton
2012-05-14 16:24 ` Joel Brobecker
1 sibling, 1 reply; 16+ messages in thread
From: Joel Brobecker @ 2012-05-14 16:21 UTC (permalink / raw)
To: Jeff Kenton; +Cc: gdb-patches
> This is part 1 of 3, containing basic support for the TILE-Gx
> processor. Patch is attached. It contains:
>
> gdb/
> * tilegx-linux-tdep.c: New file
> * tilegx-tdep.c: New file
> * configure.host: Add tilegx target.
> * configure.tgt: Add tilegx target.
> * Makefile.in: Add tilegx dependencies.
> gdb/regformats/
> * reg-tilegx.dat: New file.
>
> gdb/config/tilegx/
> * nm-linux.h: New file.
There is only one ChangeLog for all these files, IIRC (gdb/Changelog).
So it should be one single entry, and the filenames should be relative
to the gdb/ directory (Eg: `* regformat/reg-tilegx.dat, or
config/tilegx/nm-linux.h).
Can you be more specific about the changes make to Makefile.in?
In particular, say which variables were updated, and which rules
were added? Here is an example:
* Makefile.in (ALL_64_TARGET_OBS): Add ia64-hpux-tdep.o.
(HFILES_NO_SRCDIR): Add ia64-hpux-tdep.h.
(ALLDEPFILES): Add ia64-hpux-nat.c ia64-hpux-tdep.c.
You'll also need to add your config/tilegx/nm-linux.h to HFILES_NO_SRCDIR.
> +#ifndef NM_TILELINUX_H
> +#define NM_TILELINUX_H
> +
> +#undef HAVE_LINK_H
Why do you need to do this?
> +tilegx-*-linux*)
> + # Target: TILE-Gx
> + gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
> + symfile-mem.o glibc-tdep.o linux-tdep.o"
> + build_gdbserver=yes
> + ;;
You need to remove "build_gdbserver=yes" from this patch. Otherwise,
if we apply this patch but not the gdbserver bits, we'll get a build
error.
> +{
> + /* Stub. */
> +}
> +
> +
> +static const struct tramp_frame tilegx_linux_rt_sigframe =
One empty line too many (nitpick, no biggie if you like it better
this way.
> +#if 0
> +/* Target-dependent code for GNU/Linux SPARC.
> +
> + Copyright (C) 2003-2005, 2007-2012 Free Software Foundation, Inc.
I'd really not have any commented-out code creeping unless there is
a very good reason, and we know it's going to be temporary. In this
case, it even looks like it's still there by mistake???
> +/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
> + * plus 8 special general purpose registers (network and ZERO),
> + * plus 1 magic register (PC).
> + *
> + * TP (aka R53) is the thread specific data pointer.
> + * SP (aka R54) is the stack pointer.
> + * LR (aka R55) is the link register.
> + */
The comment style does not follow the GNU Coding Style (GCS). Can
you remove the extra `*' at the start of each line (except the first
one, of course)?
> +struct tilegx_frame_cache
> +{
> + /* Base address. */
> + CORE_ADDR base;
> + CORE_ADDR start_pc;
> + struct trad_frame_saved_reg *saved_regs;
> +};
Can you quickly document each field, please?
> +enum reverse_state {
> + REVERSE_STATE_REGISTER,
> + REVERSE_STATE_VALUE,
> + REVERSE_STATE_UNKNOWN
> +};
Trailing space at the end of REVERSE_STATE_VALUE. Can you document
this enum, please, as well as ...
> +struct tilegx_reverse_regs
> +{
> + LONGEST value;
> + enum reverse_state state;
> +};
... this struct?
> +static const struct tilegx_reverse_regs
> +template_reverse_regs[E_NUM_PHYS_REGS] =
Same here.
> +/* This is the implementation of gdbarch method register_name. */
This is a bit of a nitpick, but MarkK recently requested that
we try to be consistent when documeting the gdbarch method
implementations. So, can you update the variable comments and say
/* Implement the "register_name" gdbarch method. */
?
> +static int
> +tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
Please document this function.
> +static int
> +tilegx_type_is_scalar (struct type *t)
> +{
> + return (TYPE_CODE(t) != TYPE_CODE_STRUCT
> + && TYPE_CODE(t) != TYPE_CODE_UNION
> + && TYPE_CODE(t) != TYPE_CODE_ARRAY);
The indentation is wrong. The `&&' operators should be aligned with
the start of the `TYPE_CODE' macro.
> +/* Returns non-zero if the given struct type will be returned using
> + a special convention, rather than the normal function return method.
> + Used in the context of the "return" command, and target function
> + calls from the debugger. */
Trailing space at the end of the last line.
> + /* Only scalars which fit in R0 - R9 can be returned in registers.
> + Otherwise, they are returned via a pointer passed in R0. */
> + return !tilegx_type_is_scalar (type)
> + && (TYPE_LENGTH (type) > (1 + E_R9_REGNUM - E_R0_REGNUM) * tilegx_reg_size);
Same as above. Indentation issue. Also, please wrap the condition
inside parenthesis. This is not strictly necessary, but is mandated
by the GCS in order to help automatic formatters.
> +/* Find a function's return value in the appropriate registers (in
> + regbuf), and copy it into valbuf. */
> +
> +static void
> +tilegx_extract_return_value (struct type *type, struct regcache *regcache,
> + void *valbuf)
^^^^^^^^^^^^
valbuf should be a gdb_byte *.
> +{
> + int len = TYPE_LENGTH (type);
> + int i, regnum = E_R0_REGNUM;
> +
> + for (i = 0; i < len; i += tilegx_reg_size)
> + regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
Remove the cast.
> +/* Copy the function return value from VALBUF into the
> + proper location for a function return.
> + Called only in the context of the "return" command. */
Trailing space at the end of the second line. Please also reformat
to better fit 70-character lines (first line too short).
> +static void
> +tilegx_store_return_value (struct type *type, struct regcache *regcache,
> + const void *valbuf)
> +{
> + if (TYPE_LENGTH (type) < tilegx_reg_size)
> + {
Trailing spaces on 2 of the lines above.
> + /* Add leading zeros to the value. */
> + char buf[tilegx_reg_size];
Use gdb_byte instead of char.
> + for (i = 0; i < len; i += tilegx_reg_size)
> + regcache_raw_write (regcache, regnum++, (char *) valbuf + i);
Remove the cast/
> +static enum return_value_convention
> +tilegx_return_value (struct gdbarch *gdbarch, struct type *func_type,
> + struct type *type, struct regcache *regcache,
> + gdb_byte *readbuf, const gdb_byte *writebuf)
This function needs documentation.
> +static CORE_ADDR
> +tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
Same here.
> +/* Setup the function arguments for GDB to call a function in the inferior.
> + Called only in the context of a target function call from the debugger.
> + Returns the value of the SP register after the args are pushed. */
The lines are too lone (soft-limit is 70 characters). But you should
just refer to the "push_dummy_call" gdbarch method, rather than repeating
the generic documentation (if the gdbarch method is not properly
documentated, please consider submitting an independent patch that
improves it there instead).
> +static CORE_ADDR
> +tilegx_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);
> + CORE_ADDR stack_dest = sp;
> + int argreg = E_R0_REGNUM;
> + int i, j;
> + int typelen, slacklen, alignlen;
> + static const int zero_words[2] = { 0, 0 };
Can you make that a `gdb_bype two_zero_words[8] = { 0 }' instead?
> + /* Arguments are passed in R0 - R9, and as soon as an argument will not
> + fit completely in the remaining registers, then it, and all remaining
> + arguments, are put on the stack. */
Can you reformat the comment to make the lines a little shorter?
> + /* ISSUE: Why special handling (only) for "typelen = 4x + 1"?
> + I am unable to induce any "typelen" values except 4 and 8. */
> + int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
> + ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
> + regcache_cooked_write_unsigned (regcache, argreg++, w);
Empty line after last variable declaration....
> + /* Loop backwards through remaining arguments and push them on the stack,
> + wordaligned. */
Lines too long...
> + {
> + char *val;
gdb_byte *...
> + typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
Empty line after last variable declaration...
> + /* Now write this data to the stack. The stack grows downwards. */
Missing second space after period.
> + /* Add 2 words for linkage space to the stack. */
> + stack_dest = stack_dest - 8;
> + write_memory (stack_dest, (void*)zero_words, 8);
Remove the cast.
> + struct tilegx_decoded_instruction decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
> + struct tilegx_reverse_regs new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
These two lines are too long...
> + /* Initialize the reverse frame. This maps the CURRENT frame's registers
> + to the outer frame's registers (the frame on the stack goes the other
> + way). */
Lines are two long. Missing second space after period.
> + /* To cut down on round-trip overhead, we fetch multiple bundles at once.
> + * These variables describe the range of memory we have prefetched. */
Likewise.
> + /* Figure out how many bytes to fetch. Don't span a page boundary
> + since that might cause an unnecessary memory error. */
Ditto.
> + unsigned int size_on_same_page = 4096 - (next_addr & 4095);
> + instbuf_size = sizeof instbuf;
Missing empty line after variable declaration.
> + status = safe_frame_unwind_memory (next_frame, instbuf_start, instbuf,
> + instbuf_size);
Line too long.
> + bundle = extract_unsigned_integer (&instbuf[next_addr - instbuf_start],
> + 8, byte_order);
Ditto.
> + struct tilegx_decoded_instruction *this_insn = &decoded[i];
> + int64_t *operands = (int64_t *)this_insn->operand_values;
> + const struct tilegx_opcode *opcode = this_insn->opcode;
> + switch (opcode->mnemonic)
Empty line after decls.
> + {
> + case TILEGX_OPC_ST:
> + if (cache &&
Trailing space.
> + LONGEST saved_address = reverse_frame[operands[0]].value;
> + unsigned saved_register = (unsigned)reverse_frame[operands[1]].value;
Line too long. Add empty line after decls.
> + /* realreg >= 0 and addr != -1 indicates that the value
> + of saved_register is in memory location saved_address.
> + The value of realreg is not meaningful in this case but
> + it must be >= 0. See trad-frame.h */
Period at end of sentence.
> + if (cache
> + && operands[0] == E_SP_REGNUM
> + && operands[1] == E_SP_REGNUM
> + && reverse_frame[operands[1]].state ==
> + REVERSE_STATE_REGISTER)
Trailing spaces...
> + /* This is a special case. We're fixing up the stack frame. */
> + uint64_t hopefully_sp =
> + (unsigned)reverse_frame[operands[1]].value;
> + short op2_as_short = (short)operands[2];
> + signed char op2_as_char = (signed char)operands[2];
I thin we're supposed to put a space after the ')' in casts. I might
have missed some earlier. Can you fix all of them? I won't comment
on any other violations I might find later on.
> +
> + /* Fix up the sign-extension. */
> + if (opcode->mnemonic == TILEGX_OPC_ADDI)
> + op2_as_short = op2_as_char;
> + prev_sp_value = cache->saved_regs[hopefully_sp].addr - op2_as_short;
Line too long. Same thing: I will stop commenting on all style issues
such as trailing spaces, lines that are too long, missing empty line
Safter variable declarations, etc. Can you do a pass an fix them all?
The soft limit for line length is 70 characters, and you can exceed it
if sticking to 70 would make the code ugly, of your comment harder to
read (or any other valid excuse). The hard limit is 80 characters and
should always be obeyed unless you really have a good reason.
> + /* We don't know anything about the values. Punt. */
> + /* We don't know anything about the values. Punt. */
Two spaces after period. Can you also include this in your pass?
> + /* Nothing to see here, move on.
> + * Note that real NOP is treated as a 'real' instruction
> + * because someone must have intended that it be there.
> + * It therefore terminates the prolog.
> + */
Same request for this type of comments.
> + /* we're really done -- this is a branch */
Missing period at end of sentence.
> + for (i = 0; i < num_insns; i++)
> + {
> + /* ISSUE: Does this properly handle "network" registers? */
> + if ((reverse_frame_valid & (1<<i)) && dest_regs[i] != E_ZERO_REGNUM)
> + {
> + reverse_frame[dest_regs[i]] = new_reverse_frame[i];
> + }
> + }
Unnecessary curly braces for the "if" block (single statement). For
the "for" loop, they are OK, because of the comment you added.
> + if (reverse_frame[i].state == REVERSE_STATE_REGISTER
> + && reverse_frame[i].value != i)
> + {
> + unsigned saved_register = (unsigned)reverse_frame[i].value;
Add empty line.
> +/* If the input address is in a function prologue,
> + returns the address of the end of the prologue;
> + else returns the input address.
> +
> + Note: the input address is likely to be the function start,
> + since this function is mainly used for advancing a breakpoint
> + to the first line, or stepping to the first line when we have
> + stepped into a function call. */
> +
> +static CORE_ADDR
> +tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
Please document this function using a reference to the gdbarch method
instead.
> +/* The epilogue is defined here as the area at the end of a function,
> + either on the `ret' instruction itself or after an instruction which
> + destroys the function's stack frame. */
> +static int
Another little coding rule, this time specific to GDB: Empyt line
between the function documentation and the function definintion.
> +}
> +
> +
> +static const unsigned char *
You can delete the extra line, if you'd like.
> +tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
> + CORE_ADDR *pcptr, int *lenptr)
Please document this function.
> + static unsigned char breakpoint[sizeof (tilegx_bundle_bits)];
gdb_byte?
> + tilegx_bundle_bits bits = TILEGX_BPT_BUNDLE;
Where is tilegx_bundle_bits defined? I can't find it anywhere in this
patch...
> + unsigned int i;
> +
> + for (i = 0; i < sizeof (breakpoint); i++)
> + {
> + breakpoint[i] = (unsigned char)bits;
> + bits >>= 8;
> + }
I am wondering whether there might be an easier way. Isn't the
tilegx breakpoint instrction someting statically known?
> +static struct value*
> +tilegx_frame_prev_register (struct frame_info *this_frame,
> + void **this_cache,
> + int regnum)
Please document this function.
> +static void
> +tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
> + struct frame_id *this_id)
Likewise. I'll stop commenting on this as well, can you include all
other functions in your update?
> +/* This logic must match that of struct pt_regs in "ptrace.h". */
> +
> +static void
> +tilegx_linux_supply_regset (const struct regset *regset,
> + struct regcache *regcache,
> + int regnum, const void *regs, size_t len)
Please document what this function is supposed to do. I'd add your
current comment inside the function itself, as an implementation
detail.
> + int gri = (i < E_NUM_EASY_REGS) ? i : E_PC_REGNUM;
> + if (regnum == gri || regnum == -1)
Missing empty line.
> +/* Initializer function for the tilegx gdbarch vector.
> + Called by gdbarch. Sets up the gdbarch vector(s) for this target. */
You don't need to repeat what should already be documented in
the gdbarch module.
> + /* try to find a pre-existing architecture */
Missing period at end of sentence.
> + set_gdbarch_regset_from_core_section (gdbarch,
> + tilegx_regset_from_core_section);
Formatting (alignment of second parameter).
> + /*
> + * Frame Info
> + */
Comment style.
> + set_gdbarch_in_function_epilogue_p (gdbarch,
> + tilegx_in_function_epilogue_p);
Formatting.
I recomment you go through the gdbserver patch with the same comments
in mind, before you ask Pedro to review them. Otherwise, he might
have to make the same comments...
--
Joel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-11 16:09 [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb) Jeff Kenton
2012-05-14 16:21 ` Joel Brobecker
@ 2012-05-14 16:24 ` Joel Brobecker
1 sibling, 0 replies; 16+ messages in thread
From: Joel Brobecker @ 2012-05-14 16:24 UTC (permalink / raw)
To: Jeff Kenton; +Cc: gdb-patches
> gdb/
> * tilegx-linux-tdep.c: New file
> * tilegx-tdep.c: New file
> * configure.host: Add tilegx target.
> * configure.tgt: Add tilegx target.
> * Makefile.in: Add tilegx dependencies.
>
> gdb/regformats/
> * reg-tilegx.dat: New file.
>
> gdb/config/tilegx/
> * nm-linux.h: New file.
There is something I missed as well: I thought you were submitted
both target and native at the same time, but I see now that patch
#2 is taking care of the native part. IN that case, I think that
the configure.host changes are superfluous, and and nm-linux.h also.
These two should be move to patch #2.
Can you resubmit patch #2 & #3 after you've clean them up?
--
Joel
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-14 16:21 ` Joel Brobecker
@ 2012-05-21 14:23 ` Jeff Kenton
2012-05-23 17:34 ` Pedro Alves
0 siblings, 1 reply; 16+ messages in thread
From: Jeff Kenton @ 2012-05-21 14:23 UTC (permalink / raw)
To: Joel Brobecker; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 265 bytes --]
On 05/14/2012 12:20 PM, Joel Brobecker wrote:
>> ... [ Lots of comments and suggestions. ]
>>
This is part 1 of 3, containing basic support for the TILE-Gx processor.
Modified in accordance with Joel's comments. Patch attached.
Comments please.
--jeff kenton
[-- Attachment #2: patch_1 --]
[-- Type: text/plain, Size: 45199 bytes --]
gdb/
* Makefile.in (ALL_TARGET_OBJS): Add tilegx-tdep.o, tilegx-linux-tdep.o.
(ALLDEPFILES): tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c.
* configure.tgt: Add tilegx target.
* tilegx-tdep.c: New file
* tilegx-linux-tdep.c: New file
* regformats/reg-tilegx.dat: New file.
diff -r -u -N /home/packages/gdb-7.4x/gdb/configure.tgt ./gdb/configure.tgt
--- /home/packages/gdb-7.4x/gdb/configure.tgt 2012-03-05 06:41:51.000000000 -0500
+++ ./gdb/configure.tgt 2012-05-18 14:00:31.387177000 -0400
@@ -551,6 +551,13 @@
gdb_target_obs="tic6x-tdep.o"
;;
+tilegx-*-linux*)
+ # Target: TILE-Gx
+ gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
+ symfile-mem.o glibc-tdep.o linux-tdep.o"
+ ;;
+
+
xstormy16-*-*)
# Target: Sanyo Xstormy16a processor
gdb_target_obs="xstormy16-tdep.o"
diff -r -u -N /home/packages/gdb-7.4x/gdb/Makefile.in ./gdb/Makefile.in
--- /home/packages/gdb-7.4x/gdb/Makefile.in 2012-03-28 17:31:18.000000000 -0400
+++ ./gdb/Makefile.in 2012-05-18 14:00:31.295201000 -0400
@@ -565,6 +565,7 @@
sparc-sol2-tdep.o sparc-tdep.o \
spu-tdep.o spu-multiarch.o solib-spu.o \
tic6x-tdep.o tic6x-linux-tdep.o \
+ tilegx-tdep.o tilegx-linux-tdep.o \
v850-tdep.o \
vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
xstormy16-tdep.o \
@@ -1510,6 +1511,8 @@
sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
+ tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c \
+ config/tilegx/nm-linux.h \
v850-tdep.c \
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
windows-nat.c windows-tdep.c \
diff -r -u -N /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat ./gdb/regformats/reg-tilegx.dat
--- /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/regformats/reg-tilegx.dat 2012-05-18 14:00:31.508189000 -0400
@@ -0,0 +1,67 @@
+name:tile
+expedite:sp,lr,pc
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:r32
+64:r33
+64:r34
+64:r35
+64:r36
+64:r37
+64:r38
+64:r39
+64:r40
+64:r41
+64:r42
+64:r43
+64:r44
+64:r45
+64:r46
+64:r47
+64:r48
+64:r49
+64:r50
+64:r51
+64:r52
+64:tp
+64:sp
+64:lr
+64:sn
+64:io0
+64:io1
+64:us0
+64:us1
+64:us2
+64:us3
+64:zero
+64:pc
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-linux-tdep.c 2012-05-18 16:06:18.990217000 -0400
@@ -0,0 +1,77 @@
+/* Target-dependent code for GNU/Linux on Xtensa processors.
+
+ Copyright 2012 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 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 "osabi.h"
+#include "linux-tdep.h"
+#include "glibc-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "tramp-frame.h"
+#include <signal.h>
+#include <sys/ucontext.h>
+
+/* Signal trampoline support. */
+
+static void
+tilegx_linux_sigframe_init (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ /* Stub. */
+}
+
+static const struct tramp_frame tilegx_linux_rt_sigframe =
+{
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
+ { 0x286b180051485000, -1 }, /* { swint1 } */
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ tilegx_linux_sigframe_init
+};
+
+/* OS specific initialization of gdbarch. */
+
+static void
+tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ linux_init_abi (info, gdbarch);
+
+ tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
+
+ /* Shared library handling. */
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_linux_tdep;
+
+void
+_initialize_tilegx_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_tilegx, bfd_mach_tilegx, GDB_OSABI_LINUX,
+ tilegx_linux_init_abi);
+}
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.c 2012-05-21 08:09:54.479718000 -0400
@@ -0,0 +1,1164 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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 "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "dis-asm.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "regset.h"
+#include "doublest.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "objfiles.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+
+#include "opcode/tilegx.h"
+
+/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
+ plus 8 special general purpose registers (network and ZERO),
+ plus 1 magic register (PC).
+
+ TP (aka R53) is the thread specific data pointer.
+ SP (aka R54) is the stack pointer.
+ LR (aka R55) is the link register.
+ */
+enum {
+
+ E_R0_REGNUM,
+ E_R1_REGNUM,
+ E_R2_REGNUM,
+ E_R3_REGNUM,
+ E_R4_REGNUM,
+ E_R5_REGNUM,
+ E_R6_REGNUM,
+ E_R7_REGNUM,
+ E_R8_REGNUM,
+ E_R9_REGNUM,
+ E_R10_REGNUM,
+ E_R11_REGNUM,
+ E_R12_REGNUM,
+ E_R13_REGNUM,
+ E_R14_REGNUM,
+ E_R15_REGNUM,
+ E_R16_REGNUM,
+ E_R17_REGNUM,
+ E_R18_REGNUM,
+ E_R19_REGNUM,
+ E_R20_REGNUM,
+ E_R21_REGNUM,
+ E_R22_REGNUM,
+ E_R23_REGNUM,
+ E_R24_REGNUM,
+ E_R25_REGNUM,
+ E_R26_REGNUM,
+ E_R27_REGNUM,
+ E_R28_REGNUM,
+ E_R29_REGNUM,
+ E_R30_REGNUM,
+ E_R31_REGNUM,
+ E_R32_REGNUM,
+ E_R33_REGNUM,
+ E_R34_REGNUM,
+ E_R35_REGNUM,
+ E_R36_REGNUM,
+ E_R37_REGNUM,
+ E_R38_REGNUM,
+ E_R39_REGNUM,
+ E_R40_REGNUM,
+ E_R41_REGNUM,
+ E_R42_REGNUM,
+ E_R43_REGNUM,
+ E_R44_REGNUM,
+ E_R45_REGNUM,
+ E_R46_REGNUM,
+ E_R47_REGNUM,
+ E_R48_REGNUM,
+ E_R49_REGNUM,
+ E_R50_REGNUM,
+ E_R51_REGNUM,
+ E_R52_REGNUM,
+ E_TP_REGNUM,
+ E_SP_REGNUM,
+ E_LR_REGNUM,
+
+ E_SN_REGNUM, E_NUM_EASY_REGS = E_SN_REGNUM, /* 56 */
+ E_IO0_REGNUM,
+ E_IO1_REGNUM,
+ E_US0_REGNUM,
+ E_US1_REGNUM,
+ E_US2_REGNUM,
+ E_US3_REGNUM,
+ E_ZERO_REGNUM,
+
+ E_PC_REGNUM, E_NUM_PHYS_REGS = E_PC_REGNUM, /* 64 */
+
+ E_NUM_REGS /* 65 */
+};
+
+
+struct tilegx_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ CORE_ADDR start_pc;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Register state values used by analyze_prologue(). */
+enum reverse_state {
+ REVERSE_STATE_REGISTER,
+ REVERSE_STATE_VALUE,
+ REVERSE_STATE_UNKNOWN
+};
+
+/* Register state used by analyze_prologue(). */
+struct tilegx_reverse_regs
+{
+ LONGEST value;
+ enum reverse_state state;
+};
+
+static const struct tilegx_reverse_regs
+template_reverse_regs[E_NUM_PHYS_REGS] =
+ {
+ { E_R0_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R1_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R2_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R3_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R4_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R5_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R6_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R7_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R8_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R9_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R10_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R11_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R12_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R13_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R14_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R15_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R16_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R17_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R18_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R19_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R20_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R21_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R22_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R23_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R24_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R25_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R26_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R27_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R28_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R29_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R30_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R31_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R32_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R33_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R34_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R35_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R36_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R37_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R38_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R39_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R40_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R41_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R42_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R43_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R44_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R45_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R46_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R47_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R48_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R49_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R50_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R51_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R52_REGNUM, REVERSE_STATE_REGISTER },
+ { E_TP_REGNUM, REVERSE_STATE_REGISTER },
+ { E_SP_REGNUM, REVERSE_STATE_REGISTER },
+ { E_LR_REGNUM, REVERSE_STATE_REGISTER },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { E_ZERO_REGNUM, REVERSE_STATE_VALUE }
+ };
+
+
+enum { tilegx_reg_size = 8 };
+
+/* Implement the "register_name" gdbarch method. */
+
+static const char *
+tilegx_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ static const char *const register_names[E_NUM_REGS] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr",
+ "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero",
+ "pc"
+ };
+
+ if (regnum < 0 || regnum >= E_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "tilegx_register_name: illegal register number %d",
+ regnum);
+
+ return register_names[regnum];
+}
+
+/* This is the implementation of gdbarch method register_type. */
+
+static struct type *
+tilegx_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == E_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+}
+
+/* This is the implementation of gdbarch method dwarf2_reg_to_regnum. */
+
+static int
+tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ return num;
+}
+
+
+/* Makes the decision if a given type is a scalar type. Scalar
+ types are returned in the registers r2-r11 as they fit. */
+
+static int
+tilegx_type_is_scalar (struct type *t)
+{
+ return (TYPE_CODE(t) != TYPE_CODE_STRUCT
+ && TYPE_CODE(t) != TYPE_CODE_UNION
+ && TYPE_CODE(t) != TYPE_CODE_ARRAY);
+}
+
+/* Returns non-zero if the given struct type will be returned using
+ a special convention, rather than the normal function return method.
+ Used in the context of the "return" command, and target function
+ calls from the debugger. */
+
+static int
+tilegx_use_struct_convention (struct type *type)
+{
+ /* Only scalars which fit in R0 - R9 can be returned in registers.
+ Otherwise, they are returned via a pointer passed in R0. */
+ return !tilegx_type_is_scalar (type)
+ && (TYPE_LENGTH (type) > (1 + E_R9_REGNUM - E_R0_REGNUM)
+ * tilegx_reg_size);
+}
+
+/* Find a function's return value in the appropriate registers (in
+ regbuf), and copy it into valbuf. */
+
+static void
+tilegx_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ int i, regnum = E_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_read (regcache, regnum++, valbuf + i);
+}
+
+/* Copy the function return value from VALBUF into the proper
+ location for a function return.
+ Called only in the context of the "return" command. */
+
+static void
+tilegx_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ if (TYPE_LENGTH (type) < tilegx_reg_size)
+ {
+ /* Add leading zeros to the value. */
+ gdb_byte buf[tilegx_reg_size];
+
+ memset (buf, 0, tilegx_reg_size);
+ memcpy (buf, valbuf, TYPE_LENGTH (type));
+ regcache_raw_write (regcache, E_R0_REGNUM, buf);
+ }
+ else
+ {
+ int len = TYPE_LENGTH (type);
+ int i, regnum = E_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_write (regcache, regnum++, (gdb_byte *) valbuf + i);
+ }
+}
+
+/* This is the implementation of gdbarch method return_value. */
+
+static enum return_value_convention
+tilegx_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (tilegx_use_struct_convention (type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ if (writebuf)
+ tilegx_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ tilegx_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* This is the implementation of gdbarch method frame_align. */
+
+static CORE_ADDR
+tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return addr & -8;
+}
+
+
+/* Implement the "push_dummy_call" gdbarch method. */
+
+static CORE_ADDR
+tilegx_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);
+ CORE_ADDR stack_dest = sp;
+ int argreg = E_R0_REGNUM;
+ int i, j;
+ int typelen, slacklen, alignlen;
+ static const gdb_byte two_zero_words[8] = { 0 };
+
+ /* If struct_return is 1, then the struct return address will
+ consume one argument-passing register. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
+
+ /* Arguments are passed in R0 - R9, and as soon as an argument
+ will not fit completely in the remaining registers, then it,
+ and all remaining arguments, are put on the stack. */
+ for (i = 0; i < nargs && argreg <= E_R9_REGNUM; i++)
+ {
+ const char *val;
+ typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
+
+ if (typelen > (E_R9_REGNUM - argreg + 1) * tilegx_reg_size)
+ break;
+
+ /* Put argument into registers wordwise. */
+ val = value_contents (args[i]);
+ for (j = 0; j < typelen; j += tilegx_reg_size)
+ {
+ /* ISSUE: Why special handling for "typelen = 4x + 1"?
+ I don't ever see "typelen" values except 4 and 8. */
+ int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
+ ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
+
+ regcache_cooked_write_unsigned (regcache, argreg++, w);
+ }
+ }
+
+ /* Align SP. */
+ stack_dest = tilegx_frame_align (gdbarch, stack_dest);
+
+ /* Loop backwards through arguments to determine stack alignment. */
+ alignlen = 0;
+
+ for (j = nargs - 1; j >= i; j--)
+ {
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ alignlen += (typelen + 3) & (~3);
+ }
+
+ if (alignlen & 0x4)
+ stack_dest -= 4;
+
+ /* Loop backwards through remaining arguments and push them on
+ the stack, word aligned. */
+ for (j = nargs - 1; j >= i; j--)
+ {
+ gdb_byte *val;
+
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ slacklen = ((typelen + 3) & (~3)) - typelen;
+ val = alloca (typelen + slacklen);
+ memcpy (val, value_contents (args[j]), typelen);
+ memset (val + typelen, 0, slacklen);
+
+ /* Now write data to the stack. The stack grows downwards. */
+ stack_dest -= typelen + slacklen;
+ write_memory (stack_dest, val, typelen + slacklen);
+ }
+
+ /* Add 2 words for linkage space to the stack. */
+ stack_dest = stack_dest - 8;
+ write_memory (stack_dest, two_zero_words, 8);
+
+ /* Update stack pointer. */
+ regcache_cooked_write_unsigned (regcache, E_SP_REGNUM, stack_dest);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_unsigned (regcache, E_LR_REGNUM, bp_addr);
+
+ return stack_dest;
+}
+
+
+/* Decode the instructions within the given address range.
+ Decide when we must have reached the end of the function prologue.
+ If a frame_info pointer is provided, fill in its saved_regs etc.
+ Returns the address of the first instruction after the prologue.
+ NOTE: This is often called with start_addr being the start of some
+ function, and end_addr being the current PC. */
+
+static CORE_ADDR
+tilegx_analyze_prologue (struct gdbarch* gdbarch,
+ CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct tilegx_frame_cache *cache,
+ struct frame_info *next_frame)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR next_addr;
+ CORE_ADDR prolog_end = end_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+ gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
+ CORE_ADDR instbuf_start;
+ unsigned int instbuf_size;
+ int status;
+ bfd_uint64_t bundle;
+ struct tilegx_decoded_instruction
+ decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int num_insns;
+ struct tilegx_reverse_regs reverse_frame[E_NUM_PHYS_REGS];
+ struct tilegx_reverse_regs
+ new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int reverse_frame_valid, prolog_done, branch_seen;
+ LONGEST prev_sp_value;
+ int i, j;
+
+ if (start_addr >= end_addr
+ || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
+ return end_addr;
+
+ /* Initialize the reverse frame. This maps the CURRENT frame's
+ registers to the outer frame's registers (the frame on the
+ stack goes the other way). */
+ memcpy (&reverse_frame, &template_reverse_regs,
+ sizeof (reverse_frame));
+
+ prolog_done = 0;
+ branch_seen = 0;
+ prev_sp_value = 0;
+
+ /* To cut down on round-trip overhead, we fetch multiple bundles
+ at once. These variables describe the range of memory we have
+ prefetched. */
+ instbuf_start = 0;
+ instbuf_size = 0;
+
+ for (next_addr = start_addr; next_addr < end_addr;
+ next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
+ {
+ /* Retrieve the next instruction. */
+ if (next_addr - instbuf_start >= instbuf_size)
+ {
+ /* Figure out how many bytes to fetch. Don't span a page
+ boundary since that might cause an unnecessary memory
+ error. */
+ unsigned int size_on_same_page = 4096 - (next_addr & 4095);
+ instbuf_size = sizeof instbuf;
+
+ if (instbuf_size > size_on_same_page)
+ instbuf_size = size_on_same_page;
+ instbuf_start = next_addr;
+
+ status = safe_frame_unwind_memory (next_frame, instbuf_start,
+ instbuf, instbuf_size);
+ if (status == 0)
+ memory_error (status, next_addr);
+ }
+
+ reverse_frame_valid = 0;
+
+ bundle = extract_unsigned_integer (&instbuf[next_addr
+ - instbuf_start],
+ 8, byte_order);
+
+ num_insns = parse_insn_tilegx (bundle, next_addr, decoded);
+
+ for (i = 0; i < num_insns; i++)
+ {
+ struct tilegx_decoded_instruction *this_insn = &decoded[i];
+ int64_t *operands = (int64_t *) this_insn->operand_values;
+ const struct tilegx_opcode *opcode = this_insn->opcode;
+
+ switch (opcode->mnemonic)
+ {
+ case TILEGX_OPC_ST:
+ if (cache &&
+ reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].state
+ == REVERSE_STATE_REGISTER)
+ {
+ LONGEST saved_address = reverse_frame[operands[0]].value;
+ unsigned saved_register =
+ (unsigned) reverse_frame[operands[1]].value;
+
+ /* realreg >= 0 and addr != -1 indicates that the
+ value of saved_register is in memory location
+ saved_address. The value of realreg is not
+ meaningful in this case but it must be >= 0.
+ See trad-frame.h. */
+ cache->saved_regs[saved_register].realreg =
+ saved_register;
+ cache->saved_regs[saved_register].addr =
+ saved_address;
+ }
+ break;
+ case TILEGX_OPC_ADDI:
+ case TILEGX_OPC_ADDLI:
+ if (cache
+ && operands[0] == E_SP_REGNUM
+ && operands[1] == E_SP_REGNUM
+ && reverse_frame[operands[1]].state ==
+ REVERSE_STATE_REGISTER)
+ {
+ /* Special case. We're fixing up the stack frame. */
+ uint64_t hopefully_sp =
+ (unsigned) reverse_frame[operands[1]].value;
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+ prev_sp_value = cache->saved_regs[hopefully_sp].addr
+ - op2_as_short;
+
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value =
+ cache->saved_regs[hopefully_sp].addr;
+ trad_frame_set_value (cache->saved_regs,
+ hopefully_sp, prev_sp_value);
+ }
+ else
+ {
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
+ new_reverse_frame[i].value += op2_as_short;
+ else
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ADD:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ new_reverse_frame[i].value +=
+ reverse_frame[operands[i]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVE:
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVEI:
+ case TILEGX_OPC_MOVELI:
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value = operands[1];
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ORI:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have a value in A -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value =
+ reverse_frame[operands[1]].value | operands[2];
+ }
+ else if (operands[2] == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_OR:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ }
+ else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_SUB:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value -=
+ reverse_frame[operands[2]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1<<i;
+ dest_regs[i] = operands[0];
+ break;
+
+ case TILEGX_OPC_FNOP:
+ case TILEGX_OPC_INFO:
+ case TILEGX_OPC_INFOL:
+ /* Nothing to see here, move on.
+ Note that real NOP is treated as a 'real' instruction
+ because someone must have intended that it be there.
+ It therefore terminates the prolog.
+ */
+ break;
+
+ case TILEGX_OPC_J:
+ case TILEGX_OPC_JAL:
+
+ case TILEGX_OPC_BEQZ:
+ case TILEGX_OPC_BEQZT:
+ case TILEGX_OPC_BGEZ:
+ case TILEGX_OPC_BGEZT:
+ case TILEGX_OPC_BGTZ:
+ case TILEGX_OPC_BGTZT:
+ case TILEGX_OPC_BLBC:
+ case TILEGX_OPC_BLBCT:
+ case TILEGX_OPC_BLBS:
+ case TILEGX_OPC_BLBST:
+ case TILEGX_OPC_BLEZ:
+ case TILEGX_OPC_BLEZT:
+ case TILEGX_OPC_BLTZ:
+ case TILEGX_OPC_BLTZT:
+ case TILEGX_OPC_BNEZ:
+ case TILEGX_OPC_BNEZT:
+
+ case TILEGX_OPC_IRET:
+ case TILEGX_OPC_JALR:
+ case TILEGX_OPC_JALRP:
+ case TILEGX_OPC_JR:
+ case TILEGX_OPC_JRP:
+ case TILEGX_OPC_SWINT0:
+ case TILEGX_OPC_SWINT1:
+ case TILEGX_OPC_SWINT2:
+ case TILEGX_OPC_SWINT3:
+ /* We're really done -- this is a branch. */
+ branch_seen = 1;
+ prolog_done = 1;
+ break;
+ default:
+ /* We don't know or care what this instruction is.
+ All we know is that it isn't part of a prolog, and if
+ there's a destination register, we're trashing it. */
+ prolog_done = 1;
+ for (j = 0; j < opcode->num_operands; j++)
+ {
+ if (this_insn->operands[j]->is_dest_reg)
+ {
+ dest_regs[i] = operands[j];
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ reverse_frame_valid |= 1<<i;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now update the reverse frames. */
+ for (i = 0; i < num_insns; i++)
+ {
+ /* ISSUE: Does this properly handle "network" registers? */
+ if ((reverse_frame_valid & (1<<i))
+ && dest_regs[i] != E_ZERO_REGNUM)
+ reverse_frame[dest_regs[i]] = new_reverse_frame[i];
+ }
+
+ if (prev_sp_value != 0)
+ {
+ /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */
+ if (reverse_frame[E_R52_REGNUM].state == REVERSE_STATE_REGISTER
+ && reverse_frame[E_R52_REGNUM].value == E_SP_REGNUM)
+ {
+ reverse_frame[E_R52_REGNUM].state = REVERSE_STATE_VALUE;
+ reverse_frame[E_R52_REGNUM].value = prev_sp_value;
+ }
+
+ prev_sp_value = 0;
+ }
+
+ if (prolog_done && prolog_end == end_addr)
+ {
+ /* We found non-prolog code. As such, _this_ instruction
+ is the one after the prolog. We keep processing, because
+ there may be more prolog code in there, but this is what
+ we'll return. */
+ /* ISSUE: There may not have actually been a prologue, and
+ we may have simply skipped some random instructions. */
+ prolog_end = next_addr;
+ }
+ if (branch_seen)
+ {
+ /* We saw a branch. The prolog absolutely must be over. */
+ break;
+ }
+ }
+
+ if (prolog_end == end_addr && cache)
+ {
+ /* We may have terminated the prolog early, and we're certainly
+ at THIS point right now. It's possible that the values of
+ registers we need are currently actually in other registers
+ (and haven't been written to memory yet). Go find them. */
+ for (i = 0; i < E_NUM_PHYS_REGS; i++)
+ {
+ if (reverse_frame[i].state == REVERSE_STATE_REGISTER
+ && reverse_frame[i].value != i)
+ {
+ unsigned saved_register = (unsigned) reverse_frame[i].value;
+
+ cache->saved_regs[saved_register].realreg = i;
+ cache->saved_regs[saved_register].addr = (LONGEST) -1;
+ }
+ }
+ }
+
+ return prolog_end;
+}
+
+/* This is the implementation of gdbarch method skip_prologue. */
+
+static CORE_ADDR
+tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end && pc <= sal.end)
+ return sal.end;
+ }
+
+ /* Otherwise, try to skip prologue the hard way. */
+ return tilegx_analyze_prologue (gdbarch,
+ pc, pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES,
+ NULL, NULL);
+}
+
+/* This is the implementation of gdbarch method in_function_epilogue_p. */
+
+static int
+tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0, func_end = 0;
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ ULONGEST inst, inst2;
+ CORE_ADDR addr = func_end - TILEGX_BUNDLE_SIZE_IN_BYTES;
+
+ /* FIXME: Find the actual epilogue. */
+ /* HACK: Just assume the final bundle is the "ret" instruction". */
+ if (pc > addr)
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the implementation of gdbarch method breakpoint_from_pc. */
+
+static const unsigned char *
+tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
+{
+ /* 64-bit pattern for a { bpt ; nop } bundle. */
+ static unsigned char breakpoint[] =
+ { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+/* Normal frames. */
+
+static struct tilegx_frame_cache *
+tilegx_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct tilegx_frame_cache *cache;
+ CORE_ADDR current_pc;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct tilegx_frame_cache);
+ *this_cache = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+ cache->base = 0;
+ cache->start_pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+
+ cache->base = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
+ trad_frame_set_value (cache->saved_regs, E_SP_REGNUM, cache->base);
+
+ cache->saved_regs[E_PC_REGNUM] = cache->saved_regs[E_LR_REGNUM];
+
+ if (cache->start_pc)
+ tilegx_analyze_prologue (gdbarch, cache->start_pc, current_pc,
+ cache, this_frame);
+
+ return cache;
+}
+
+/* Retrieve the value of REGNUM in FRAME. */
+
+static struct value*
+tilegx_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int regnum)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs,
+ regnum);
+}
+
+/* Build frame id. */
+static void
+tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (info->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (info->base, info->start_pc);
+}
+
+static CORE_ADDR
+tilegx_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct tilegx_frame_cache *cache =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_unwind tilegx_frame_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ tilegx_frame_this_id,
+ tilegx_frame_prev_register,
+ NULL, /* const struct frame_data *unwind_data */
+ default_frame_sniffer, /* frame_sniffer_ftype *sniffer */
+ NULL /* frame_prev_pc_ftype *prev_pc */
+};
+
+static const struct frame_base tilegx_frame_base = {
+ &tilegx_frame_unwind,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address
+};
+
+static CORE_ADDR
+tilegx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_SP_REGNUM);
+}
+
+static CORE_ADDR
+tilegx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_PC_REGNUM);
+}
+
+static struct frame_id
+tilegx_unwind_dummy_id (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+
+ sp = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+
+/* We cannot read/write the "special" registers. */
+
+static int
+tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno)
+{
+ if (regno >= 0 && regno < E_NUM_EASY_REGS)
+ return 0;
+ else if (regno == E_PC_REGNUM)
+ return 0;
+ else
+ return 1;
+}
+
+/* Supply raw registers from REGCACHE to REGS. */
+
+static void
+tilegx_linux_supply_regset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *regs, size_t len)
+{
+ struct gdbarch *arch = get_regcache_arch (regcache);
+ const char *ptr = regs;
+ int i;
+
+ /* This logic must match that of struct pt_regs in "ptrace.h". */
+ for (i = 0; i < E_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size)
+ {
+ int gri = (i < E_NUM_EASY_REGS) ? i : E_PC_REGNUM;
+
+ if (regnum == gri || regnum == -1)
+ regcache_raw_supply (regcache, gri, ptr);
+ }
+}
+
+
+/* TILE-Gx Linux kernal register set. */
+static struct regset tilegx_linux_regset =
+{
+ NULL,
+ tilegx_linux_supply_regset
+};
+
+static const struct regset *
+tilegx_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ if (strcmp (sect_name, ".reg") == 0)
+ return &tilegx_linux_regset;
+
+ return NULL;
+}
+
+static struct gdbarch *
+tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ int arch_size = 64;
+
+ /* Handle arch_size == 32 or 64. Default to 64. */
+ if (info.abfd)
+ arch_size = bfd_get_arch_size (info.abfd);
+
+ if (arch_size != 32)
+ arch_size = 64;
+
+ /* Try to find a pre-existing architecture. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* We only have two flavors -- just make sure arch_size matches. */
+ if (gdbarch_ptr_bit (arches->gdbarch) == arch_size)
+ return (arches->gdbarch);
+ }
+
+ gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Basic register fields and methods, datatype sizes and stuff. */
+
+ /* There are 64 physical registers which can be referenced by
+ instructions (although only 56 of them can actually be
+ debugged) and 1 magic register (the PC). The other three
+ magic registers (ex1, syscall, orig_r0) which are known to
+ "ptrace" are ignored by "gdb". Note that we simply pretend
+ that there are 65 registers, and no "pseudo registers". */
+ set_gdbarch_num_regs (gdbarch, E_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+ set_gdbarch_sp_regnum (gdbarch, E_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, E_PC_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, tilegx_register_name);
+ set_gdbarch_register_type (gdbarch, tilegx_register_type);
+
+ set_gdbarch_char_signed (gdbarch, 0);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, arch_size);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_ptr_bit (gdbarch, arch_size);
+ set_gdbarch_addr_bit (gdbarch, arch_size);
+
+ set_gdbarch_cannot_fetch_register (gdbarch,
+ tilegx_cannot_reference_register);
+ set_gdbarch_cannot_store_register (gdbarch,
+ tilegx_cannot_reference_register);
+
+ set_gdbarch_regset_from_core_section (gdbarch,
+ tilegx_regset_from_core_section);
+
+ /* Stack grows down. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Frame Info. */
+ set_gdbarch_unwind_sp (gdbarch, tilegx_unwind_sp);
+ set_gdbarch_unwind_pc (gdbarch, tilegx_unwind_pc);
+ set_gdbarch_dummy_id (gdbarch, tilegx_unwind_dummy_id);
+ set_gdbarch_frame_align (gdbarch, tilegx_frame_align);
+ frame_base_set_default (gdbarch, &tilegx_frame_base);
+
+ set_gdbarch_skip_prologue (gdbarch, tilegx_skip_prologue);
+
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ tilegx_in_function_epilogue_p);
+
+ /* Map debug registers into internal register numbers. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, tilegx_dwarf2_reg_to_regnum);
+
+ /* These values and methods are used when gdb calls a target function. */
+ set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call);
+ set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc);
+ set_gdbarch_return_value (gdbarch, tilegx_return_value);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_tilegx);
+
+ /* GNU/Linux uses SVR4-style shared libraries. */
+ if (arch_size == 32)
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+ else
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
+
+ gdbarch_init_osabi (info, gdbarch);
+
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &tilegx_frame_unwind);
+
+ return gdbarch;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_tdep;
+
+void
+_initialize_tilegx_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
+}
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-21 14:23 ` Jeff Kenton
@ 2012-05-23 17:34 ` Pedro Alves
2012-05-24 19:26 ` Jeff Kenton
0 siblings, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-05-23 17:34 UTC (permalink / raw)
To: Jeff Kenton; +Cc: Joel Brobecker, gdb-patches
Hi Jeff,
On 05/21/2012 03:23 PM, Jeff Kenton wrote:
> gdb/
> * Makefile.in (ALL_TARGET_OBJS): Add tilegx-tdep.o, tilegx-linux-tdep.o.
> (ALLDEPFILES): tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c.
^
"Add " missing.
> * configure.tgt: Add tilegx target.
> * tilegx-tdep.c: New file
Missing period.
> * tilegx-linux-tdep.c: New file
Missing period.
> * regformats/reg-tilegx.dat: New file.
>
> diff -r -u -N /home/packages/gdb-7.4x/gdb/configure.tgt ./gdb/configure.tgt
> --- /home/packages/gdb-7.4x/gdb/configure.tgt 2012-03-05 06:41:51.000000000 -0500
> +++ ./gdb/configure.tgt 2012-05-18 14:00:31.387177000 -0400
> @@ -551,6 +551,13 @@
> gdb_target_obs="tic6x-tdep.o"
> ;;
>
> +tilegx-*-linux*)
> + # Target: TILE-Gx
> + gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
> + symfile-mem.o glibc-tdep.o linux-tdep.o"
> + ;;
> +
> +
> xstormy16-*-*)
> # Target: Sanyo Xstormy16a processor
> gdb_target_obs="xstormy16-tdep.o"
> diff -r -u -N /home/packages/gdb-7.4x/gdb/Makefile.in ./gdb/Makefile.in
> --- /home/packages/gdb-7.4x/gdb/Makefile.in 2012-03-28 17:31:18.000000000 -0400
> +++ ./gdb/Makefile.in 2012-05-18 14:00:31.295201000 -0400
> @@ -565,6 +565,7 @@
> sparc-sol2-tdep.o sparc-tdep.o \
> spu-tdep.o spu-multiarch.o solib-spu.o \
> tic6x-tdep.o tic6x-linux-tdep.o \
> + tilegx-tdep.o tilegx-linux-tdep.o \
> v850-tdep.o \
> vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
> xstormy16-tdep.o \
> @@ -1510,6 +1511,8 @@
> sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
> sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
> spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
> + tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c \
> + config/tilegx/nm-linux.h \
"config/tilegx/nm-linux.h" shouldn't be here.
> v850-tdep.c \
> vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
> windows-nat.c windows-tdep.c \
> diff -r -u -N /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat ./gdb/regformats/reg-tilegx.dat
> --- /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat 1969-12-31 19:00:00.000000000 -0500
> +++ ./gdb/regformats/reg-tilegx.dat 2012-05-18 14:00:31.508189000 -0400
> @@ -0,0 +1,67 @@
> +name:tile
> +expedite:sp,lr,pc
> +64:r0
> +64:r1
> +64:r2
> +64:r3
> +64:r4
> +64:r5
> +64:r6
> +64:r7
> +64:r8
> +64:r9
> +64:r10
> +64:r11
> +64:r12
> +64:r13
> +64:r14
> +64:r15
> +64:r16
> +64:r17
> +64:r18
> +64:r19
> +64:r20
> +64:r21
> +64:r22
> +64:r23
> +64:r24
> +64:r25
> +64:r26
> +64:r27
> +64:r28
> +64:r29
> +64:r30
> +64:r31
> +64:r32
> +64:r33
> +64:r34
> +64:r35
> +64:r36
> +64:r37
> +64:r38
> +64:r39
> +64:r40
> +64:r41
> +64:r42
> +64:r43
> +64:r44
> +64:r45
> +64:r46
> +64:r47
> +64:r48
> +64:r49
> +64:r50
> +64:r51
> +64:r52
> +64:tp
> +64:sp
> +64:lr
> +64:sn
> +64:io0
> +64:io1
> +64:us0
> +64:us1
> +64:us2
> +64:us3
> +64:zero
> +64:pc
> diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
> --- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
> +++ ./gdb/tilegx-linux-tdep.c 2012-05-18 16:06:18.990217000 -0400
> @@ -0,0 +1,77 @@
> +/* Target-dependent code for GNU/Linux on Xtensa processors.
> +
> + Copyright 2012 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 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 "osabi.h"
> +#include "linux-tdep.h"
> +#include "glibc-tdep.h"
> +#include "solib-svr4.h"
> +#include "symtab.h"
> +#include "tramp-frame.h"
> +#include <signal.h>
> +#include <sys/ucontext.h>
These last two system includes are a sign of something not being host
independent here. But I don't think you need them?
> +
> +/* Signal trampoline support. */
> +
> +static void
> +tilegx_linux_sigframe_init (const struct tramp_frame *self,
> + struct frame_info *this_frame,
> + struct trad_frame_cache *this_cache,
> + CORE_ADDR func)
> +{
> + /* Stub. */
> +}
> +
> +static const struct tramp_frame tilegx_linux_rt_sigframe =
> +{
> + SIGTRAMP_FRAME,
> + 4,
> + {
> + { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
> + { 0x286b180051485000, -1 }, /* { swint1 } */
> + { TRAMP_SENTINEL_INSN, -1 }
> + },
> + tilegx_linux_sigframe_init
> +};
> +
> +/* OS specific initialization of gdbarch. */
> +
> +static void
> +tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> + linux_init_abi (info, gdbarch);
> +
> + tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
> +
> + /* Shared library handling. */
> + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
> + set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
> +
> + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
> +}
> +
> +/* Provide a prototype to silence -Wmissing-prototypes. */
> +extern initialize_file_ftype _initialize_tilegx_linux_tdep;
> +
> +void
> +_initialize_tilegx_linux_tdep (void)
> +{
> + gdbarch_register_osabi (bfd_arch_tilegx, bfd_mach_tilegx, GDB_OSABI_LINUX,
> + tilegx_linux_init_abi);
> +}
> diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
> --- /home/packages/gdb-7.4x/gdb/tilegx-tdep.c 1969-12-31 19:00:00.000000000 -0500
> +++ ./gdb/tilegx-tdep.c 2012-05-21 08:09:54.479718000 -0400
> @@ -0,0 +1,1164 @@
> +/* Target-dependent code for the Tilera TILE-Gx processor.
> +
> + Copyright (C) 2012 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 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 "frame.h"
> +#include "frame-base.h"
> +#include "frame-unwind.h"
> +#include "dwarf2-frame.h"
> +#include "trad-frame.h"
> +#include "symtab.h"
> +#include "gdbtypes.h"
> +#include "gdbcmd.h"
> +#include "gdbcore.h"
> +#include "value.h"
> +#include "dis-asm.h"
> +#include "inferior.h"
> +#include "gdb_string.h"
> +#include "gdb_assert.h"
> +#include "arch-utils.h"
> +#include "floatformat.h"
> +#include "regcache.h"
> +#include "regset.h"
> +#include "doublest.h"
> +#include "osabi.h"
> +#include "linux-tdep.h"
> +#include "objfiles.h"
> +#include "solib-svr4.h"
> +#include "symtab.h"
> +
> +#include "opcode/tilegx.h"
> +
> +/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
> + plus 8 special general purpose registers (network and ZERO),
> + plus 1 magic register (PC).
> +
> + TP (aka R53) is the thread specific data pointer.
> + SP (aka R54) is the stack pointer.
> + LR (aka R55) is the link register.
> + */
> +enum {
> +
> + E_R0_REGNUM,
Correct formatting is:
enum
{
E_R0_REGNUM,
> + E_R1_REGNUM,
> + E_R2_REGNUM,
> + E_R3_REGNUM,
> + E_R4_REGNUM,
> + E_R5_REGNUM,
> + E_R6_REGNUM,
> + E_R7_REGNUM,
> + E_R8_REGNUM,
> + E_R9_REGNUM,
> + E_R10_REGNUM,
> + E_R11_REGNUM,
> + E_R12_REGNUM,
> + E_R13_REGNUM,
> + E_R14_REGNUM,
> + E_R15_REGNUM,
> + E_R16_REGNUM,
> + E_R17_REGNUM,
> + E_R18_REGNUM,
> + E_R19_REGNUM,
> + E_R20_REGNUM,
> + E_R21_REGNUM,
> + E_R22_REGNUM,
> + E_R23_REGNUM,
> + E_R24_REGNUM,
> + E_R25_REGNUM,
> + E_R26_REGNUM,
> + E_R27_REGNUM,
> + E_R28_REGNUM,
> + E_R29_REGNUM,
> + E_R30_REGNUM,
> + E_R31_REGNUM,
> + E_R32_REGNUM,
> + E_R33_REGNUM,
> + E_R34_REGNUM,
> + E_R35_REGNUM,
> + E_R36_REGNUM,
> + E_R37_REGNUM,
> + E_R38_REGNUM,
> + E_R39_REGNUM,
> + E_R40_REGNUM,
> + E_R41_REGNUM,
> + E_R42_REGNUM,
> + E_R43_REGNUM,
> + E_R44_REGNUM,
> + E_R45_REGNUM,
> + E_R46_REGNUM,
> + E_R47_REGNUM,
> + E_R48_REGNUM,
> + E_R49_REGNUM,
> + E_R50_REGNUM,
> + E_R51_REGNUM,
> + E_R52_REGNUM,
> + E_TP_REGNUM,
> + E_SP_REGNUM,
> + E_LR_REGNUM,
> +
> + E_SN_REGNUM, E_NUM_EASY_REGS = E_SN_REGNUM, /* 56 */
> + E_IO0_REGNUM,
> + E_IO1_REGNUM,
> + E_US0_REGNUM,
> + E_US1_REGNUM,
> + E_US2_REGNUM,
> + E_US3_REGNUM,
> + E_ZERO_REGNUM,
> +
> + E_PC_REGNUM, E_NUM_PHYS_REGS = E_PC_REGNUM, /* 64 */
> +
> + E_NUM_REGS /* 65 */
> +};
> +
> +
> +struct tilegx_frame_cache
> +{
> + /* Base address. */
> + CORE_ADDR base;
> + CORE_ADDR start_pc;
Missing comment on this field.
> +
> + /* Table of saved registers. */
> + struct trad_frame_saved_reg *saved_regs;
> +};
> +
> +/* Register state values used by analyze_prologue(). */
> +enum reverse_state {
> + REVERSE_STATE_REGISTER,
enum reverse_state
{
REVERSE_STATE_REGISTER,
> +/* Register state used by analyze_prologue(). */
Don't write "analyze_prologue()" when referring to a function.
Just write "analyze_prologue".
> +struct tilegx_reverse_regs
> +{
> + LONGEST value;
> + enum reverse_state state;
> +};
> +
> +static const struct tilegx_reverse_regs
> +template_reverse_regs[E_NUM_PHYS_REGS] =
> + {
> + { E_R0_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R1_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R2_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R3_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R4_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R5_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R6_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R7_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R8_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R9_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R10_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R11_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R12_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R13_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R14_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R15_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R16_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R17_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R18_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R19_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R20_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R21_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R22_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R23_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R24_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R25_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R26_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R27_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R28_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R29_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R30_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R31_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R32_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R33_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R34_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R35_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R36_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R37_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R38_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R39_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R40_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R41_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R42_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R43_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R44_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R45_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R46_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R47_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R48_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R49_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R50_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R51_REGNUM, REVERSE_STATE_REGISTER },
> + { E_R52_REGNUM, REVERSE_STATE_REGISTER },
> + { E_TP_REGNUM, REVERSE_STATE_REGISTER },
> + { E_SP_REGNUM, REVERSE_STATE_REGISTER },
> + { E_LR_REGNUM, REVERSE_STATE_REGISTER },
> + { 0, REVERSE_STATE_UNKNOWN },
> + { 0, REVERSE_STATE_UNKNOWN },
> + { 0, REVERSE_STATE_UNKNOWN },
> + { 0, REVERSE_STATE_UNKNOWN },
> + { 0, REVERSE_STATE_UNKNOWN },
> + { 0, REVERSE_STATE_UNKNOWN },
> + { 0, REVERSE_STATE_UNKNOWN },
> + { E_ZERO_REGNUM, REVERSE_STATE_VALUE }
> + };
> +
> +
> +enum { tilegx_reg_size = 8 };
> +
> +/* Returns non-zero if the given struct type will be returned using
> + a special convention, rather than the normal function return method.
> + Used in the context of the "return" command, and target function
> + calls from the debugger. */
> +
> +static int
> +tilegx_use_struct_convention (struct type *type)
> +{
> + /* Only scalars which fit in R0 - R9 can be returned in registers.
> + Otherwise, they are returned via a pointer passed in R0. */
> + return !tilegx_type_is_scalar (type)
> + && (TYPE_LENGTH (type) > (1 + E_R9_REGNUM - E_R0_REGNUM)
> + * tilegx_reg_size);
> +}
> +
> +/* Find a function's return value in the appropriate registers (in
> + regbuf), and copy it into valbuf. */
> +
> +static void
> +tilegx_extract_return_value (struct type *type, struct regcache *regcache,
> + gdb_byte *valbuf)
> +{
> + int len = TYPE_LENGTH (type);
> + int i, regnum = E_R0_REGNUM;
> +
> + for (i = 0; i < len; i += tilegx_reg_size)
> + regcache_raw_read (regcache, regnum++, valbuf + i);
> +}
> +
> +/* Copy the function return value from VALBUF into the proper
> + location for a function return.
> + Called only in the context of the "return" command. */
> +
> +static void
> +tilegx_store_return_value (struct type *type, struct regcache *regcache,
> + const void *valbuf)
> +{
> + if (TYPE_LENGTH (type) < tilegx_reg_size)
> + {
> + /* Add leading zeros to the value. */
You say "leading", but zeros are added at the end? Or this an endian thing?
> + gdb_byte buf[tilegx_reg_size];
> +
> + memset (buf, 0, tilegx_reg_size);
You can just write:
gdb_byte buf[tilegx_reg_size] = { 0 };
> + memcpy (buf, valbuf, TYPE_LENGTH (type));
> + regcache_raw_write (regcache, E_R0_REGNUM, buf);
> + }
> + else
> + {
> + int len = TYPE_LENGTH (type);
> + int i, regnum = E_R0_REGNUM;
> +
> + for (i = 0; i < len; i += tilegx_reg_size)
> + regcache_raw_write (regcache, regnum++, (gdb_byte *) valbuf + i);
> + }
> +}
> +
> +/* This is the implementation of gdbarch method return_value. */
> +
> +static enum return_value_convention
> +tilegx_return_value (struct gdbarch *gdbarch, struct type *func_type,
> + struct type *type, struct regcache *regcache,
> + gdb_byte *readbuf, const gdb_byte *writebuf)
> +{
> + if (tilegx_use_struct_convention (type))
> + return RETURN_VALUE_STRUCT_CONVENTION;
> + if (writebuf)
> + tilegx_store_return_value (type, regcache, writebuf);
> + else if (readbuf)
> + tilegx_extract_return_value (type, regcache, readbuf);
> + return RETURN_VALUE_REGISTER_CONVENTION;
> +}
> +
> +/* This is the implementation of gdbarch method frame_align. */
> +
> +static CORE_ADDR
> +tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
> +{
> + return addr & -8;
> +}
> +
> +
> +/* Implement the "push_dummy_call" gdbarch method. */
> +
> +static CORE_ADDR
> +tilegx_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);
> + CORE_ADDR stack_dest = sp;
> + int argreg = E_R0_REGNUM;
> + int i, j;
> + int typelen, slacklen, alignlen;
> + static const gdb_byte two_zero_words[8] = { 0 };
> +
> + /* If struct_return is 1, then the struct return address will
> + consume one argument-passing register. */
> + if (struct_return)
> + regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
> +
> + /* Arguments are passed in R0 - R9, and as soon as an argument
> + will not fit completely in the remaining registers, then it,
> + and all remaining arguments, are put on the stack. */
> + for (i = 0; i < nargs && argreg <= E_R9_REGNUM; i++)
> + {
> + const char *val;
gdb_byte
> + typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
> +
> + if (typelen > (E_R9_REGNUM - argreg + 1) * tilegx_reg_size)
> + break;
> +
> + /* Put argument into registers wordwise. */
> + val = value_contents (args[i]);
> + for (j = 0; j < typelen; j += tilegx_reg_size)
> + {
> + /* ISSUE: Why special handling for "typelen = 4x + 1"?
> + I don't ever see "typelen" values except 4 and 8. */
> + int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
> + ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
> +
> + regcache_cooked_write_unsigned (regcache, argreg++, w);
> + }
> + }
> +
> + /* Align SP. */
> + stack_dest = tilegx_frame_align (gdbarch, stack_dest);
> +
> + /* Loop backwards through arguments to determine stack alignment. */
> + alignlen = 0;
> +
> + for (j = nargs - 1; j >= i; j--)
> + {
> + typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
> + alignlen += (typelen + 3) & (~3);
> + }
> +
> + if (alignlen & 0x4)
> + stack_dest -= 4;
> +
> + /* Loop backwards through remaining arguments and push them on
> + the stack, word aligned. */
> + for (j = nargs - 1; j >= i; j--)
> + {
> + gdb_byte *val;
> +
> + typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
> + slacklen = ((typelen + 3) & (~3)) - typelen;
> + val = alloca (typelen + slacklen);
> + memcpy (val, value_contents (args[j]), typelen);
> + memset (val + typelen, 0, slacklen);
> +
> + /* Now write data to the stack. The stack grows downwards. */
> + stack_dest -= typelen + slacklen;
> + write_memory (stack_dest, val, typelen + slacklen);
> + }
> +
> + /* Add 2 words for linkage space to the stack. */
> + stack_dest = stack_dest - 8;
> + write_memory (stack_dest, two_zero_words, 8);
> +
> + /* Update stack pointer. */
> + regcache_cooked_write_unsigned (regcache, E_SP_REGNUM, stack_dest);
> +
> + /* Set the return address register to point to the entry point of
> + the program, where a breakpoint lies in wait. */
> + regcache_cooked_write_unsigned (regcache, E_LR_REGNUM, bp_addr);
> +
> + return stack_dest;
> +}
> +
> +
> +/* Decode the instructions within the given address range.
> + Decide when we must have reached the end of the function prologue.
> + If a frame_info pointer is provided, fill in its saved_regs etc.
> + Returns the address of the first instruction after the prologue.
> + NOTE: This is often called with start_addr being the start of some
> + function, and end_addr being the current PC. */
> +
> +static CORE_ADDR
> +tilegx_analyze_prologue (struct gdbarch* gdbarch,
> + CORE_ADDR start_addr, CORE_ADDR end_addr,
> + struct tilegx_frame_cache *cache,
> + struct frame_info *next_frame)
> +{
> + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + CORE_ADDR next_addr;
> + CORE_ADDR prolog_end = end_addr;
> + ULONGEST inst, inst2;
> + LONGEST offset;
> + int regnum;
> + gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
> + CORE_ADDR instbuf_start;
> + unsigned int instbuf_size;
> + int status;
> + bfd_uint64_t bundle;
> + struct tilegx_decoded_instruction
> + decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
> + int num_insns;
> + struct tilegx_reverse_regs reverse_frame[E_NUM_PHYS_REGS];
> + struct tilegx_reverse_regs
> + new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
> + int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
> + int reverse_frame_valid, prolog_done, branch_seen;
> + LONGEST prev_sp_value;
> + int i, j;
> +
> + if (start_addr >= end_addr
> + || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
> + return end_addr;
> +
> + /* Initialize the reverse frame. This maps the CURRENT frame's
> + registers to the outer frame's registers (the frame on the
> + stack goes the other way). */
> + memcpy (&reverse_frame, &template_reverse_regs,
> + sizeof (reverse_frame));
> +
> + prolog_done = 0;
> + branch_seen = 0;
> + prev_sp_value = 0;
> +
> + /* To cut down on round-trip overhead, we fetch multiple bundles
> + at once. These variables describe the range of memory we have
> + prefetched. */
> + instbuf_start = 0;
> + instbuf_size = 0;
> +
> + for (next_addr = start_addr; next_addr < end_addr;
> + next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
> + {
> + /* Retrieve the next instruction. */
> + if (next_addr - instbuf_start >= instbuf_size)
> + {
> + /* Figure out how many bytes to fetch. Don't span a page
> + boundary since that might cause an unnecessary memory
> + error. */
> + unsigned int size_on_same_page = 4096 - (next_addr & 4095);
> + instbuf_size = sizeof instbuf;
> +
> + if (instbuf_size > size_on_same_page)
> + instbuf_size = size_on_same_page;
> + instbuf_start = next_addr;
> +
> + status = safe_frame_unwind_memory (next_frame, instbuf_start,
> + instbuf, instbuf_size);
> + if (status == 0)
> + memory_error (status, next_addr);
> + }
> +
> + reverse_frame_valid = 0;
> +
> + bundle = extract_unsigned_integer (&instbuf[next_addr
> + - instbuf_start],
> + 8, byte_order);
> +
> + num_insns = parse_insn_tilegx (bundle, next_addr, decoded);
> +
> + for (i = 0; i < num_insns; i++)
> + {
> + struct tilegx_decoded_instruction *this_insn = &decoded[i];
> + int64_t *operands = (int64_t *) this_insn->operand_values;
> + const struct tilegx_opcode *opcode = this_insn->opcode;
> +
> + switch (opcode->mnemonic)
> + {
> + case TILEGX_OPC_ST:
> + if (cache &&
> + reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
Operator at the beginning of the next line:
if (cache
&& reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
> + && reverse_frame[operands[1]].state
> + == REVERSE_STATE_REGISTER)
> + {
> + LONGEST saved_address = reverse_frame[operands[0]].value;
> + unsigned saved_register =
> + (unsigned) reverse_frame[operands[1]].value;
Likewise:
unsigned saved_register
= (unsigned) reverse_frame[operands[1]].value;
> +
> + /* realreg >= 0 and addr != -1 indicates that the
> + value of saved_register is in memory location
> + saved_address. The value of realreg is not
> + meaningful in this case but it must be >= 0.
> + See trad-frame.h. */
> + cache->saved_regs[saved_register].realreg =
> + saved_register;
> + cache->saved_regs[saved_register].addr =
> + saved_address;
Likewise. Though it looks like it could fit a single line.
> + }
> + break;
> + case TILEGX_OPC_ADDI:
> + case TILEGX_OPC_ADDLI:
> + if (cache
> + && operands[0] == E_SP_REGNUM
> + && operands[1] == E_SP_REGNUM
> + && reverse_frame[operands[1]].state ==
> + REVERSE_STATE_REGISTER)
> + {
> + /* Special case. We're fixing up the stack frame. */
> + uint64_t hopefully_sp =
> + (unsigned) reverse_frame[operands[1]].value;
Likewise. Many more instances.
> + short op2_as_short = (short) operands[2];
> + signed char op2_as_char = (signed char) operands[2];
> +
> + /* Fix up the sign-extension. */
> + if (opcode->mnemonic == TILEGX_OPC_ADDI)
> + op2_as_short = op2_as_char;
> + prev_sp_value = cache->saved_regs[hopefully_sp].addr
> + - op2_as_short;
Wrap multiline expressions in in ()'s and reindent:
prev_sp_value = (cache->saved_regs[hopefully_sp].addr
- op2_as_short);
> +
> + new_reverse_frame[i].state = REVERSE_STATE_VALUE;
> + new_reverse_frame[i].value =
> + cache->saved_regs[hopefully_sp].addr;
> + trad_frame_set_value (cache->saved_regs,
> + hopefully_sp, prev_sp_value);
> + }
> + else
> + {
> + short op2_as_short = (short) operands[2];
> + signed char op2_as_char = (signed char) operands[2];
> +
> + /* Fix up the sign-extension. */
> + if (opcode->mnemonic == TILEGX_OPC_ADDI)
> + op2_as_short = op2_as_char;
> +
> + new_reverse_frame[i] = reverse_frame[operands[1]];
> + if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
> + new_reverse_frame[i].value += op2_as_short;
> + else
> + new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
> + }
> + reverse_frame_valid |= 1<<i;
Missing spaces around "<<". Can i be > 31? If so, this is undefined. More instances of this.
> + dest_regs[i] = operands[0];
> + break;
> + case TILEGX_OPC_ADD:
> + if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
> + && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
> + {
> + /* We have values -- we can do this. */
> + new_reverse_frame[i] = reverse_frame[operands[2]];
> + new_reverse_frame[i].value +=
> + reverse_frame[operands[i]].value;
> + }
> + else
> + {
> + /* We don't know anything about the values. Punt. */
> + new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
> + }
> + reverse_frame_valid |= 1<<i;
> + dest_regs[i] = operands[0];
> + break;
> + case TILEGX_OPC_MOVE:
> + new_reverse_frame[i] = reverse_frame[operands[1]];
> + reverse_frame_valid |= 1<<i;
> + dest_regs[i] = operands[0];
> + break;
> + case TILEGX_OPC_MOVEI:
> + case TILEGX_OPC_MOVELI:
> + new_reverse_frame[i].state = REVERSE_STATE_VALUE;
> + new_reverse_frame[i].value = operands[1];
> + reverse_frame_valid |= 1<<i;
> + dest_regs[i] = operands[0];
> + break;
> + case TILEGX_OPC_ORI:
> + if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
> + {
> + /* We have a value in A -- we can do this. */
> + new_reverse_frame[i] = reverse_frame[operands[1]];
> + new_reverse_frame[i].value =
> + reverse_frame[operands[1]].value | operands[2];
> + }
> + else if (operands[2] == 0)
> + {
> + /* This is a move. */
> + new_reverse_frame[i] = reverse_frame[operands[1]];
> + }
> + else
> + {
> + /* We don't know anything about the values. Punt. */
> + new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
> + }
> + reverse_frame_valid |= 1<<i;
> + dest_regs[i] = operands[0];
> + break;
> + case TILEGX_OPC_OR:
> + if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
> + && reverse_frame[operands[1]].value == 0)
> + {
> + /* This is a move. */
> + new_reverse_frame[i] = reverse_frame[operands[2]];
> + }
> + else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
> + && reverse_frame[operands[2]].value == 0)
> + {
> + /* This is a move. */
> + new_reverse_frame[i] = reverse_frame[operands[1]];
> + }
> + else
> + {
> + /* We don't know anything about the values. Punt. */
> + new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
> + }
> + reverse_frame_valid |= 1<<i;
> + dest_regs[i] = operands[0];
> + break;
> + case TILEGX_OPC_SUB:
> + if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
> + && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
> + {
> + /* We have values -- we can do this. */
> + new_reverse_frame[i] = reverse_frame[operands[1]];
> + new_reverse_frame[i].value -=
> + reverse_frame[operands[2]].value;
> + }
> + else
> + {
> + /* We don't know anything about the values. Punt. */
> + new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
> + }
> + reverse_frame_valid |= 1<<i;
> + dest_regs[i] = operands[0];
> + break;
> +
> + case TILEGX_OPC_FNOP:
> + case TILEGX_OPC_INFO:
> + case TILEGX_OPC_INFOL:
> + /* Nothing to see here, move on.
> + Note that real NOP is treated as a 'real' instruction
> + because someone must have intended that it be there.
> + It therefore terminates the prolog.
> + */
> + break;
> +
> + case TILEGX_OPC_J:
> + case TILEGX_OPC_JAL:
> +
> + case TILEGX_OPC_BEQZ:
> + case TILEGX_OPC_BEQZT:
> + case TILEGX_OPC_BGEZ:
> + case TILEGX_OPC_BGEZT:
> + case TILEGX_OPC_BGTZ:
> + case TILEGX_OPC_BGTZT:
> + case TILEGX_OPC_BLBC:
> + case TILEGX_OPC_BLBCT:
> + case TILEGX_OPC_BLBS:
> + case TILEGX_OPC_BLBST:
> + case TILEGX_OPC_BLEZ:
> + case TILEGX_OPC_BLEZT:
> + case TILEGX_OPC_BLTZ:
> + case TILEGX_OPC_BLTZT:
> + case TILEGX_OPC_BNEZ:
> + case TILEGX_OPC_BNEZT:
> +
> + case TILEGX_OPC_IRET:
> + case TILEGX_OPC_JALR:
> + case TILEGX_OPC_JALRP:
> + case TILEGX_OPC_JR:
> + case TILEGX_OPC_JRP:
> + case TILEGX_OPC_SWINT0:
> + case TILEGX_OPC_SWINT1:
> + case TILEGX_OPC_SWINT2:
> + case TILEGX_OPC_SWINT3:
> + /* We're really done -- this is a branch. */
> + branch_seen = 1;
> + prolog_done = 1;
> + break;
> + default:
> + /* We don't know or care what this instruction is.
> + All we know is that it isn't part of a prolog, and if
> + there's a destination register, we're trashing it. */
> + prolog_done = 1;
> + for (j = 0; j < opcode->num_operands; j++)
> + {
> + if (this_insn->operands[j]->is_dest_reg)
> + {
> + dest_regs[i] = operands[j];
> + new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
> + reverse_frame_valid |= 1<<i;
> + break;
> + }
> + }
> + break;
> + }
> + }
> +
> + /* Now update the reverse frames. */
> + for (i = 0; i < num_insns; i++)
> + {
> + /* ISSUE: Does this properly handle "network" registers? */
> + if ((reverse_frame_valid & (1<<i))
> + && dest_regs[i] != E_ZERO_REGNUM)
> + reverse_frame[dest_regs[i]] = new_reverse_frame[i];
> + }
> +
> + if (prev_sp_value != 0)
> + {
> + /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */
> + if (reverse_frame[E_R52_REGNUM].state == REVERSE_STATE_REGISTER
> + && reverse_frame[E_R52_REGNUM].value == E_SP_REGNUM)
> + {
> + reverse_frame[E_R52_REGNUM].state = REVERSE_STATE_VALUE;
> + reverse_frame[E_R52_REGNUM].value = prev_sp_value;
> + }
> +
> + prev_sp_value = 0;
> + }
> +
> + if (prolog_done && prolog_end == end_addr)
> + {
> + /* We found non-prolog code. As such, _this_ instruction
> + is the one after the prolog. We keep processing, because
> + there may be more prolog code in there, but this is what
> + we'll return. */
> + /* ISSUE: There may not have actually been a prologue, and
> + we may have simply skipped some random instructions. */
> + prolog_end = next_addr;
> + }
> + if (branch_seen)
> + {
> + /* We saw a branch. The prolog absolutely must be over. */
> + break;
> + }
> + }
> +
> + if (prolog_end == end_addr && cache)
> + {
> + /* We may have terminated the prolog early, and we're certainly
> + at THIS point right now. It's possible that the values of
> + registers we need are currently actually in other registers
> + (and haven't been written to memory yet). Go find them. */
> + for (i = 0; i < E_NUM_PHYS_REGS; i++)
> + {
> + if (reverse_frame[i].state == REVERSE_STATE_REGISTER
> + && reverse_frame[i].value != i)
> + {
> + unsigned saved_register = (unsigned) reverse_frame[i].value;
> +
> + cache->saved_regs[saved_register].realreg = i;
> + cache->saved_regs[saved_register].addr = (LONGEST) -1;
> + }
> + }
> + }
> +
> + return prolog_end;
> +}
> +
> +/* This is the implementation of gdbarch method skip_prologue. */
> +
> +static CORE_ADDR
> +tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{
> + struct symtab_and_line sal;
> + CORE_ADDR func_start, func_end;
> +
> + /* This is the preferred method, find the end of the prologue by
> + using the debugging information. */
> + if (find_pc_partial_function (pc, NULL, &func_start, &func_end))
> + {
> + sal = find_pc_line (func_start, 0);
> +
> + if (sal.end < func_end && pc <= sal.end)
> + return sal.end;
> + }
> +
> + /* Otherwise, try to skip prologue the hard way. */
> + return tilegx_analyze_prologue (gdbarch,
> + pc, pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES,
> + NULL, NULL);
> +}
> +
> +/* This is the implementation of gdbarch method in_function_epilogue_p. */
> +
> +static int
> +tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
> +{
> + CORE_ADDR func_addr = 0, func_end = 0;
> +
> + if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
> + {
> + ULONGEST inst, inst2;
> + CORE_ADDR addr = func_end - TILEGX_BUNDLE_SIZE_IN_BYTES;
> +
> + /* FIXME: Find the actual epilogue. */
> + /* HACK: Just assume the final bundle is the "ret" instruction". */
> + if (pc > addr)
> + return 1;
> + }
> + return 0;
> +}
> +
> +/* This is the implementation of gdbarch method breakpoint_from_pc. */
> +
> +static const unsigned char *
> +tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
> + CORE_ADDR *pcptr, int *lenptr)
> +{
> + /* 64-bit pattern for a { bpt ; nop } bundle. */
> + static unsigned char breakpoint[] =
> + { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
> +
> + *lenptr = sizeof (breakpoint);
> + return breakpoint;
> +}
> +
> +/* Normal frames. */
> +
> +static struct tilegx_frame_cache *
> +tilegx_frame_cache (struct frame_info *this_frame, void **this_cache)
> +{
> + struct gdbarch *gdbarch = get_frame_arch (this_frame);
> + struct tilegx_frame_cache *cache;
> + CORE_ADDR current_pc;
> + int i;
> +
> + if (*this_cache)
> + return *this_cache;
> +
> + cache = FRAME_OBSTACK_ZALLOC (struct tilegx_frame_cache);
> + *this_cache = cache;
> + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
> + cache->base = 0;
> + cache->start_pc = get_frame_func (this_frame);
> + current_pc = get_frame_pc (this_frame);
> +
> + cache->base = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
> + trad_frame_set_value (cache->saved_regs, E_SP_REGNUM, cache->base);
> +
> + cache->saved_regs[E_PC_REGNUM] = cache->saved_regs[E_LR_REGNUM];
> +
> + if (cache->start_pc)
> + tilegx_analyze_prologue (gdbarch, cache->start_pc, current_pc,
> + cache, this_frame);
> +
> + return cache;
> +}
> +
> +/* Retrieve the value of REGNUM in FRAME. */
> +
> +static struct value*
> +tilegx_frame_prev_register (struct frame_info *this_frame,
> + void **this_cache,
> + int regnum)
> +{
> + struct tilegx_frame_cache *info =
> + tilegx_frame_cache (this_frame, this_cache);
> +
> + return trad_frame_get_prev_register (this_frame, info->saved_regs,
> + regnum);
> +}
> +
> +/* Build frame id. */
> +static void
Missing empty line.
> +tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
> + struct frame_id *this_id)
> +{
> + struct tilegx_frame_cache *info =
> + tilegx_frame_cache (this_frame, this_cache);
> +
> + /* This marks the outermost frame. */
> + if (info->base == 0)
> + return;
> +
> + (*this_id) = frame_id_build (info->base, info->start_pc);
> +}
> +
> +static CORE_ADDR
> +tilegx_frame_base_address (struct frame_info *this_frame, void **this_cache)
> +{
> + struct tilegx_frame_cache *cache =
> + tilegx_frame_cache (this_frame, this_cache);
> +
> + return cache->base;
> +}
> +
> +static const struct frame_unwind tilegx_frame_unwind = {
> + NORMAL_FRAME,
> + default_frame_unwind_stop_reason,
> + tilegx_frame_this_id,
> + tilegx_frame_prev_register,
> + NULL, /* const struct frame_data *unwind_data */
> + default_frame_sniffer, /* frame_sniffer_ftype *sniffer */
> + NULL /* frame_prev_pc_ftype *prev_pc */
> +};
> +
> +static const struct frame_base tilegx_frame_base = {
> + &tilegx_frame_unwind,
> + tilegx_frame_base_address,
> + tilegx_frame_base_address,
> + tilegx_frame_base_address
> +};
> +
> +static CORE_ADDR
> +tilegx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
> +{
> + return frame_unwind_register_unsigned (next_frame, E_SP_REGNUM);
> +}
> +
> +static CORE_ADDR
> +tilegx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
> +{
> + return frame_unwind_register_unsigned (next_frame, E_PC_REGNUM);
> +}
> +
> +static struct frame_id
> +tilegx_unwind_dummy_id (struct gdbarch *gdbarch,
> + struct frame_info *this_frame)
> +{
> + CORE_ADDR sp;
> +
> + sp = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
> + return frame_id_build (sp, get_frame_pc (this_frame));
> +}
> +
> +
> +/* We cannot read/write the "special" registers. */
> +
> +static int
> +tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno)
> +{
> + if (regno >= 0 && regno < E_NUM_EASY_REGS)
> + return 0;
> + else if (regno == E_PC_REGNUM)
> + return 0;
> + else
> + return 1;
> +}
> +
> +/* Supply raw registers from REGCACHE to REGS. */
> +
> +static void
> +tilegx_linux_supply_regset (const struct regset *regset,
> + struct regcache *regcache,
> + int regnum, const void *regs, size_t len)
> +{
> + struct gdbarch *arch = get_regcache_arch (regcache);
> + const char *ptr = regs;
> + int i;
> +
> + /* This logic must match that of struct pt_regs in "ptrace.h". */
> + for (i = 0; i < E_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size)
> + {
> + int gri = (i < E_NUM_EASY_REGS) ? i : E_PC_REGNUM;
> +
> + if (regnum == gri || regnum == -1)
> + regcache_raw_supply (regcache, gri, ptr);
> + }
> +}
> +
> +
> +/* TILE-Gx Linux kernal register set. */
Typo, "kernel".
> +static struct regset tilegx_linux_regset =
> +{
> + NULL,
> + tilegx_linux_supply_regset
> +};
> +
> +static const struct regset *
> +tilegx_regset_from_core_section (struct gdbarch *gdbarch,
> + const char *sect_name,
> + size_t sect_size)
> +{
> + if (strcmp (sect_name, ".reg") == 0)
> + return &tilegx_linux_regset;
> +
> + return NULL;
> +}
> +
Any reason these Linux specific things aren't in the linux tdep file?
If no good reason, please move them.
> +static struct gdbarch *
> +tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
> +{
> + struct gdbarch *gdbarch;
> + int arch_size = 64;
> +
> + /* Handle arch_size == 32 or 64. Default to 64. */
> + if (info.abfd)
> + arch_size = bfd_get_arch_size (info.abfd);
> +
> + if (arch_size != 32)
> + arch_size = 64;
> +
> + /* Try to find a pre-existing architecture. */
> + for (arches = gdbarch_list_lookup_by_info (arches, &info);
> + arches != NULL;
> + arches = gdbarch_list_lookup_by_info (arches->next, &info))
> + {
> + /* We only have two flavors -- just make sure arch_size matches. */
> + if (gdbarch_ptr_bit (arches->gdbarch) == arch_size)
> + return (arches->gdbarch);
> + }
> +
> + gdbarch = gdbarch_alloc (&info, NULL);
> +
> + /* Basic register fields and methods, datatype sizes and stuff. */
> +
> + /* There are 64 physical registers which can be referenced by
> + instructions (although only 56 of them can actually be
> + debugged) and 1 magic register (the PC). The other three
> + magic registers (ex1, syscall, orig_r0) which are known to
> + "ptrace" are ignored by "gdb". Note that we simply pretend
> + that there are 65 registers, and no "pseudo registers". */
> + set_gdbarch_num_regs (gdbarch, E_NUM_REGS);
> + set_gdbarch_num_pseudo_regs (gdbarch, 0);
> +
> + set_gdbarch_sp_regnum (gdbarch, E_SP_REGNUM);
> + set_gdbarch_pc_regnum (gdbarch, E_PC_REGNUM);
> +
> + set_gdbarch_register_name (gdbarch, tilegx_register_name);
> + set_gdbarch_register_type (gdbarch, tilegx_register_type);
> +
> + set_gdbarch_char_signed (gdbarch, 0);
> + set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
> + set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
> + set_gdbarch_long_bit (gdbarch, arch_size);
> + set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
> +
> + set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
> + set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
> + set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
> +
> + set_gdbarch_ptr_bit (gdbarch, arch_size);
> + set_gdbarch_addr_bit (gdbarch, arch_size);
> +
> + set_gdbarch_cannot_fetch_register (gdbarch,
> + tilegx_cannot_reference_register);
> + set_gdbarch_cannot_store_register (gdbarch,
> + tilegx_cannot_reference_register);
> +
> + set_gdbarch_regset_from_core_section (gdbarch,
> + tilegx_regset_from_core_section);
> +
> + /* Stack grows down. */
> + set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
> +
> + /* Frame Info. */
> + set_gdbarch_unwind_sp (gdbarch, tilegx_unwind_sp);
> + set_gdbarch_unwind_pc (gdbarch, tilegx_unwind_pc);
> + set_gdbarch_dummy_id (gdbarch, tilegx_unwind_dummy_id);
> + set_gdbarch_frame_align (gdbarch, tilegx_frame_align);
> + frame_base_set_default (gdbarch, &tilegx_frame_base);
> +
> + set_gdbarch_skip_prologue (gdbarch, tilegx_skip_prologue);
> +
> + set_gdbarch_in_function_epilogue_p (gdbarch,
> + tilegx_in_function_epilogue_p);
> +
> + /* Map debug registers into internal register numbers. */
> + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, tilegx_dwarf2_reg_to_regnum);
> +
> + /* These values and methods are used when gdb calls a target function. */
> + set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call);
> + set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc);
> + set_gdbarch_return_value (gdbarch, tilegx_return_value);
> +
> + set_gdbarch_print_insn (gdbarch, print_insn_tilegx);
> +
> + /* GNU/Linux uses SVR4-style shared libraries. */
> + if (arch_size == 32)
> + set_solib_svr4_fetch_link_map_offsets (gdbarch,
> + svr4_ilp32_fetch_link_map_offsets);
> + else
> + set_solib_svr4_fetch_link_map_offsets (gdbarch,
> + svr4_lp64_fetch_link_map_offsets);
> +
> + /* Enable TLS support. */
> + set_gdbarch_fetch_tls_load_module_address (gdbarch,
> + svr4_fetch_objfile_link_map);
More GNU/Linux things.
> +
> + gdbarch_init_osabi (info, gdbarch);
> +
> + dwarf2_append_unwinders (gdbarch);
> + frame_unwind_append_unwinder (gdbarch, &tilegx_frame_unwind);
> +
> + return gdbarch;
> +}
> +
> +/* Provide a prototype to silence -Wmissing-prototypes. */
> +extern initialize_file_ftype _initialize_tilegx_tdep;
> +
> +void
> +_initialize_tilegx_tdep (void)
> +{
> + register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
> +}
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-23 17:34 ` Pedro Alves
@ 2012-05-24 19:26 ` Jeff Kenton
2012-05-25 15:17 ` Pedro Alves
0 siblings, 1 reply; 16+ messages in thread
From: Jeff Kenton @ 2012-05-24 19:26 UTC (permalink / raw)
To: Pedro Alves; +Cc: Joel Brobecker, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 222 bytes --]
On 05/23/2012 01:33 PM, Pedro Alves wrote:
> Hi Jeff,
>
> On 05/21/2012 03:23 PM, Jeff Kenton wrote:
>
>
- Comments applied.
- SIGTRAMP frame handling improved.
- Patch attached.
Comments?
Thanks.
--jeff kenton
[-- Attachment #2: patch_1 --]
[-- Type: text/plain, Size: 46396 bytes --]
gdb/
* Makefile.in (ALL_TARGET_OBJS): Add tilegx-tdep.o, tilegx-linux-tdep.o.
(ALLDEPFILES): Add tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c.
* configure.tgt: Add tilegx target.
* tilegx-tdep.c: New file.
* tilegx-linux-tdep.c: New file.
* regformats/reg-tilegx.dat: New file.
diff -r -u -N /home/packages/gdb-7.4x/gdb/configure.tgt ./gdb/configure.tgt
--- /home/packages/gdb-7.4x/gdb/configure.tgt 2012-03-05 06:41:51.000000000 -0500
+++ ./gdb/configure.tgt 2012-05-24 13:43:29.962304000 -0400
@@ -551,6 +551,13 @@
gdb_target_obs="tic6x-tdep.o"
;;
+tilegx-*-linux*)
+ # Target: TILE-Gx
+ gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
+ symfile-mem.o glibc-tdep.o linux-tdep.o"
+ ;;
+
+
xstormy16-*-*)
# Target: Sanyo Xstormy16a processor
gdb_target_obs="xstormy16-tdep.o"
diff -r -u -N /home/packages/gdb-7.4x/gdb/Makefile.in ./gdb/Makefile.in
--- /home/packages/gdb-7.4x/gdb/Makefile.in 2012-03-28 17:31:18.000000000 -0400
+++ ./gdb/Makefile.in 2012-05-24 13:43:29.885277000 -0400
@@ -565,6 +565,7 @@
sparc-sol2-tdep.o sparc-tdep.o \
spu-tdep.o spu-multiarch.o solib-spu.o \
tic6x-tdep.o tic6x-linux-tdep.o \
+ tilegx-tdep.o tilegx-linux-tdep.o \
v850-tdep.o \
vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
xstormy16-tdep.o \
@@ -1510,6 +1511,7 @@
sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
+ tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c \
v850-tdep.c \
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
windows-nat.c windows-tdep.c \
diff -r -u -N /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat ./gdb/regformats/reg-tilegx.dat
--- /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/regformats/reg-tilegx.dat 2012-05-24 13:43:30.066270000 -0400
@@ -0,0 +1,67 @@
+name:tile
+expedite:sp,lr,pc
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:r32
+64:r33
+64:r34
+64:r35
+64:r36
+64:r37
+64:r38
+64:r39
+64:r40
+64:r41
+64:r42
+64:r43
+64:r44
+64:r45
+64:r46
+64:r47
+64:r48
+64:r49
+64:r50
+64:r51
+64:r52
+64:tp
+64:sp
+64:lr
+64:sn
+64:io0
+64:io1
+64:us0
+64:us1
+64:us2
+64:us3
+64:zero
+64:pc
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-linux-tdep.c 2012-05-24 13:43:30.089276000 -0400
@@ -0,0 +1,165 @@
+/* Target-dependent code for GNU/Linux on Xtensa processors.
+
+ Copyright 2012 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 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 "osabi.h"
+#include "linux-tdep.h"
+#include "glibc-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "regcache.h"
+#include "regset.h"
+#include "tramp-frame.h"
+#include "trad-frame.h"
+
+/* Signal trampoline support. */
+
+static void
+tilegx_linux_sigframe_init (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ CORE_ADDR pc = get_frame_register_unsigned (this_frame, 64);
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, 54);
+ CORE_ADDR base = sp + 16;
+ int i;
+
+ for (i = 0; i < 56; i++)
+ trad_frame_set_reg_addr (this_cache, i, base + i * 8);
+
+ trad_frame_set_reg_value (this_cache, 64, pc);
+
+ /* Save a frame ID. */
+ trad_frame_set_id (this_cache, frame_id_build (base, func));
+}
+
+static const struct tramp_frame tilegx_linux_rt_sigframe =
+{
+ SIGTRAMP_FRAME,
+ 8,
+ {
+ { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
+ { 0x286b180051485000, -1 }, /* { swint1 } */
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ tilegx_linux_sigframe_init
+};
+
+/* Supply raw registers from REGCACHE to REGS. */
+
+/* TILE-Gx has 56 general purpose registers,
+ plus 8 special general purpose registers (network and ZERO),
+ plus 1 magic register (PC == 64).
+ We only need the following 2 enums here. */
+
+enum {
+ E_NUM_EASY_REGS = 56,
+ E_PC_REGNUM = 64
+};
+
+enum { tilegx_reg_size = 8 };
+
+static void
+tilegx_linux_supply_regset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *regs, size_t len)
+{
+ struct gdbarch *arch = get_regcache_arch (regcache);
+ const char *ptr = regs;
+ int i;
+
+ /* This logic must match that of struct pt_regs in "ptrace.h". */
+ for (i = 0; i < E_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size)
+ {
+ int gri = (i < E_NUM_EASY_REGS) ? i : E_PC_REGNUM;
+
+ if (regnum == gri || regnum == -1)
+ regcache_raw_supply (regcache, gri, ptr);
+ }
+}
+
+
+/* TILE-Gx Linux kernel register set. */
+static struct regset tilegx_linux_regset =
+{
+ NULL,
+ tilegx_linux_supply_regset
+};
+
+static const struct regset *
+tilegx_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ if (strcmp (sect_name, ".reg") == 0)
+ return &tilegx_linux_regset;
+
+ return NULL;
+}
+
+/* OS specific initialization of gdbarch. */
+
+static void
+tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ int arch_size = 64;
+
+ /* Handle arch_size == 32 or 64. Default to 64. */
+ if (info.abfd)
+ arch_size = bfd_get_arch_size (info.abfd);
+
+ if (arch_size != 32)
+ arch_size = 64;
+
+ linux_init_abi (info, gdbarch);
+
+ tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
+
+ set_gdbarch_regset_from_core_section (gdbarch,
+ tilegx_regset_from_core_section);
+
+ /* GNU/Linux uses SVR4-style shared libraries. */
+ if (arch_size == 32)
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+ else
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
+
+ /* Shared library handling. */
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_linux_tdep;
+
+void
+_initialize_tilegx_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_tilegx, bfd_mach_tilegx, GDB_OSABI_LINUX,
+ tilegx_linux_init_abi);
+}
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.c 2012-05-24 13:43:30.003262000 -0400
@@ -0,0 +1,1105 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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 "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "dis-asm.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "regset.h"
+#include "doublest.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "objfiles.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+
+#include "opcode/tilegx.h"
+
+/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
+ plus 8 special general purpose registers (network and ZERO),
+ plus 1 magic register (PC).
+
+ TP (aka R53) is the thread specific data pointer.
+ SP (aka R54) is the stack pointer.
+ LR (aka R55) is the link register.
+ */
+enum {
+ E_R0_REGNUM,
+ E_R1_REGNUM,
+ E_R2_REGNUM,
+ E_R3_REGNUM,
+ E_R4_REGNUM,
+ E_R5_REGNUM,
+ E_R6_REGNUM,
+ E_R7_REGNUM,
+ E_R8_REGNUM,
+ E_R9_REGNUM,
+ E_R10_REGNUM,
+ E_R11_REGNUM,
+ E_R12_REGNUM,
+ E_R13_REGNUM,
+ E_R14_REGNUM,
+ E_R15_REGNUM,
+ E_R16_REGNUM,
+ E_R17_REGNUM,
+ E_R18_REGNUM,
+ E_R19_REGNUM,
+ E_R20_REGNUM,
+ E_R21_REGNUM,
+ E_R22_REGNUM,
+ E_R23_REGNUM,
+ E_R24_REGNUM,
+ E_R25_REGNUM,
+ E_R26_REGNUM,
+ E_R27_REGNUM,
+ E_R28_REGNUM,
+ E_R29_REGNUM,
+ E_R30_REGNUM,
+ E_R31_REGNUM,
+ E_R32_REGNUM,
+ E_R33_REGNUM,
+ E_R34_REGNUM,
+ E_R35_REGNUM,
+ E_R36_REGNUM,
+ E_R37_REGNUM,
+ E_R38_REGNUM,
+ E_R39_REGNUM,
+ E_R40_REGNUM,
+ E_R41_REGNUM,
+ E_R42_REGNUM,
+ E_R43_REGNUM,
+ E_R44_REGNUM,
+ E_R45_REGNUM,
+ E_R46_REGNUM,
+ E_R47_REGNUM,
+ E_R48_REGNUM,
+ E_R49_REGNUM,
+ E_R50_REGNUM,
+ E_R51_REGNUM,
+ E_R52_REGNUM,
+ E_TP_REGNUM,
+ E_SP_REGNUM,
+ E_LR_REGNUM,
+
+ E_SN_REGNUM, E_NUM_EASY_REGS = E_SN_REGNUM, /* 56 */
+ E_IO0_REGNUM,
+ E_IO1_REGNUM,
+ E_US0_REGNUM,
+ E_US1_REGNUM,
+ E_US2_REGNUM,
+ E_US3_REGNUM,
+ E_ZERO_REGNUM,
+
+ E_PC_REGNUM, E_NUM_PHYS_REGS = E_PC_REGNUM, /* 64 */
+
+ E_NUM_REGS /* 65 */
+};
+
+
+struct tilegx_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ /* Function start. */
+ CORE_ADDR start_pc;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Register state values used by analyze_prologue. */
+enum reverse_state {
+ REVERSE_STATE_REGISTER,
+ REVERSE_STATE_VALUE,
+ REVERSE_STATE_UNKNOWN
+};
+
+/* Register state used by analyze_prologue(). */
+struct tilegx_reverse_regs
+{
+ LONGEST value;
+ enum reverse_state state;
+};
+
+static const struct tilegx_reverse_regs
+template_reverse_regs[E_NUM_PHYS_REGS] =
+ {
+ { E_R0_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R1_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R2_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R3_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R4_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R5_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R6_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R7_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R8_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R9_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R10_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R11_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R12_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R13_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R14_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R15_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R16_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R17_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R18_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R19_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R20_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R21_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R22_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R23_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R24_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R25_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R26_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R27_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R28_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R29_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R30_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R31_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R32_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R33_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R34_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R35_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R36_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R37_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R38_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R39_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R40_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R41_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R42_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R43_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R44_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R45_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R46_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R47_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R48_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R49_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R50_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R51_REGNUM, REVERSE_STATE_REGISTER },
+ { E_R52_REGNUM, REVERSE_STATE_REGISTER },
+ { E_TP_REGNUM, REVERSE_STATE_REGISTER },
+ { E_SP_REGNUM, REVERSE_STATE_REGISTER },
+ { E_LR_REGNUM, REVERSE_STATE_REGISTER },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { E_ZERO_REGNUM, REVERSE_STATE_VALUE }
+ };
+
+
+enum { tilegx_reg_size = 8 };
+
+/* Implement the "register_name" gdbarch method. */
+
+static const char *
+tilegx_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ static const char *const register_names[E_NUM_REGS] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr",
+ "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero",
+ "pc"
+ };
+
+ if (regnum < 0 || regnum >= E_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "tilegx_register_name: illegal register number %d",
+ regnum);
+
+ return register_names[regnum];
+}
+
+/* This is the implementation of gdbarch method register_type. */
+
+static struct type *
+tilegx_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == E_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+}
+
+/* This is the implementation of gdbarch method dwarf2_reg_to_regnum. */
+
+static int
+tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ return num;
+}
+
+
+/* Makes the decision if a given type is a scalar type. Scalar
+ types are returned in the registers r2-r11 as they fit. */
+
+static int
+tilegx_type_is_scalar (struct type *t)
+{
+ return (TYPE_CODE(t) != TYPE_CODE_STRUCT
+ && TYPE_CODE(t) != TYPE_CODE_UNION
+ && TYPE_CODE(t) != TYPE_CODE_ARRAY);
+}
+
+/* Returns non-zero if the given struct type will be returned using
+ a special convention, rather than the normal function return method.
+ Used in the context of the "return" command, and target function
+ calls from the debugger. */
+
+static int
+tilegx_use_struct_convention (struct type *type)
+{
+ /* Only scalars which fit in R0 - R9 can be returned in registers.
+ Otherwise, they are returned via a pointer passed in R0. */
+ return !tilegx_type_is_scalar (type)
+ && (TYPE_LENGTH (type) > (1 + E_R9_REGNUM - E_R0_REGNUM)
+ * tilegx_reg_size);
+}
+
+/* Find a function's return value in the appropriate registers (in
+ regbuf), and copy it into valbuf. */
+
+static void
+tilegx_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ int i, regnum = E_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_read (regcache, regnum++, valbuf + i);
+}
+
+/* Copy the function return value from VALBUF into the proper
+ location for a function return.
+ Called only in the context of the "return" command. */
+
+static void
+tilegx_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ if (TYPE_LENGTH (type) < tilegx_reg_size)
+ {
+ /* Add leading zeros to the (little-endian) value. */
+ gdb_byte buf[tilegx_reg_size] = { 0 };
+
+ memcpy (buf, valbuf, TYPE_LENGTH (type));
+ regcache_raw_write (regcache, E_R0_REGNUM, buf);
+ }
+ else
+ {
+ int len = TYPE_LENGTH (type);
+ int i, regnum = E_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_write (regcache, regnum++, (gdb_byte *) valbuf + i);
+ }
+}
+
+/* This is the implementation of gdbarch method return_value. */
+
+static enum return_value_convention
+tilegx_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (tilegx_use_struct_convention (type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ if (writebuf)
+ tilegx_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ tilegx_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* This is the implementation of gdbarch method frame_align. */
+
+static CORE_ADDR
+tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return addr & -8;
+}
+
+
+/* Implement the "push_dummy_call" gdbarch method. */
+
+static CORE_ADDR
+tilegx_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);
+ CORE_ADDR stack_dest = sp;
+ int argreg = E_R0_REGNUM;
+ int i, j;
+ int typelen, slacklen, alignlen;
+ static const gdb_byte two_zero_words[8] = { 0 };
+
+ /* If struct_return is 1, then the struct return address will
+ consume one argument-passing register. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
+
+ /* Arguments are passed in R0 - R9, and as soon as an argument
+ will not fit completely in the remaining registers, then it,
+ and all remaining arguments, are put on the stack. */
+ for (i = 0; i < nargs && argreg <= E_R9_REGNUM; i++)
+ {
+ const gdb_byte *val;
+ typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
+
+ if (typelen > (E_R9_REGNUM - argreg + 1) * tilegx_reg_size)
+ break;
+
+ /* Put argument into registers wordwise. */
+ val = value_contents (args[i]);
+ for (j = 0; j < typelen; j += tilegx_reg_size)
+ {
+ /* ISSUE: Why special handling for "typelen = 4x + 1"?
+ I don't ever see "typelen" values except 4 and 8. */
+ int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
+ ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
+
+ regcache_cooked_write_unsigned (regcache, argreg++, w);
+ }
+ }
+
+ /* Align SP. */
+ stack_dest = tilegx_frame_align (gdbarch, stack_dest);
+
+ /* Loop backwards through arguments to determine stack alignment. */
+ alignlen = 0;
+
+ for (j = nargs - 1; j >= i; j--)
+ {
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ alignlen += (typelen + 3) & (~3);
+ }
+
+ if (alignlen & 0x4)
+ stack_dest -= 4;
+
+ /* Loop backwards through remaining arguments and push them on
+ the stack, word aligned. */
+ for (j = nargs - 1; j >= i; j--)
+ {
+ gdb_byte *val;
+
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ slacklen = ((typelen + 3) & (~3)) - typelen;
+ val = alloca (typelen + slacklen);
+ memcpy (val, value_contents (args[j]), typelen);
+ memset (val + typelen, 0, slacklen);
+
+ /* Now write data to the stack. The stack grows downwards. */
+ stack_dest -= typelen + slacklen;
+ write_memory (stack_dest, val, typelen + slacklen);
+ }
+
+ /* Add 2 words for linkage space to the stack. */
+ stack_dest = stack_dest - 8;
+ write_memory (stack_dest, two_zero_words, 8);
+
+ /* Update stack pointer. */
+ regcache_cooked_write_unsigned (regcache, E_SP_REGNUM, stack_dest);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_unsigned (regcache, E_LR_REGNUM, bp_addr);
+
+ return stack_dest;
+}
+
+
+/* Decode the instructions within the given address range.
+ Decide when we must have reached the end of the function prologue.
+ If a frame_info pointer is provided, fill in its saved_regs etc.
+ Returns the address of the first instruction after the prologue.
+ NOTE: This is often called with start_addr being the start of some
+ function, and end_addr being the current PC. */
+
+static CORE_ADDR
+tilegx_analyze_prologue (struct gdbarch* gdbarch,
+ CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct tilegx_frame_cache *cache,
+ struct frame_info *next_frame)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR next_addr;
+ CORE_ADDR prolog_end = end_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+ gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
+ CORE_ADDR instbuf_start;
+ unsigned int instbuf_size;
+ int status;
+ bfd_uint64_t bundle;
+ struct tilegx_decoded_instruction
+ decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int num_insns;
+ struct tilegx_reverse_regs reverse_frame[E_NUM_PHYS_REGS];
+ struct tilegx_reverse_regs
+ new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int reverse_frame_valid, prolog_done, branch_seen;
+ LONGEST prev_sp_value;
+ int i, j;
+
+ if (start_addr >= end_addr
+ || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
+ return end_addr;
+
+ /* Initialize the reverse frame. This maps the CURRENT frame's
+ registers to the outer frame's registers (the frame on the
+ stack goes the other way). */
+ memcpy (&reverse_frame, &template_reverse_regs,
+ sizeof (reverse_frame));
+
+ prolog_done = 0;
+ branch_seen = 0;
+ prev_sp_value = 0;
+
+ /* To cut down on round-trip overhead, we fetch multiple bundles
+ at once. These variables describe the range of memory we have
+ prefetched. */
+ instbuf_start = 0;
+ instbuf_size = 0;
+
+ for (next_addr = start_addr; next_addr < end_addr;
+ next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
+ {
+ /* Retrieve the next instruction. */
+ if (next_addr - instbuf_start >= instbuf_size)
+ {
+ /* Figure out how many bytes to fetch. Don't span a page
+ boundary since that might cause an unnecessary memory
+ error. */
+ unsigned int size_on_same_page = 4096 - (next_addr & 4095);
+ instbuf_size = sizeof instbuf;
+
+ if (instbuf_size > size_on_same_page)
+ instbuf_size = size_on_same_page;
+ instbuf_start = next_addr;
+
+ status = safe_frame_unwind_memory (next_frame, instbuf_start,
+ instbuf, instbuf_size);
+ if (status == 0)
+ memory_error (status, next_addr);
+ }
+
+ reverse_frame_valid = 0;
+
+ bundle = extract_unsigned_integer (&instbuf[next_addr
+ - instbuf_start],
+ 8, byte_order);
+
+ num_insns = parse_insn_tilegx (bundle, next_addr, decoded);
+
+ for (i = 0; i < num_insns; i++)
+ {
+ struct tilegx_decoded_instruction *this_insn = &decoded[i];
+ int64_t *operands = (int64_t *) this_insn->operand_values;
+ const struct tilegx_opcode *opcode = this_insn->opcode;
+
+ switch (opcode->mnemonic)
+ {
+ case TILEGX_OPC_ST:
+ if (cache
+ && reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].state
+ == REVERSE_STATE_REGISTER)
+ {
+ LONGEST saved_address = reverse_frame[operands[0]].value;
+ unsigned saved_register
+ = (unsigned) reverse_frame[operands[1]].value;
+
+ /* realreg >= 0 and addr != -1 indicates that the
+ value of saved_register is in memory location
+ saved_address. The value of realreg is not
+ meaningful in this case but it must be >= 0.
+ See trad-frame.h. */
+ cache->saved_regs[saved_register].realreg = saved_register;
+ cache->saved_regs[saved_register].addr = saved_address;
+ }
+ break;
+ case TILEGX_OPC_ADDI:
+ case TILEGX_OPC_ADDLI:
+ if (cache
+ && operands[0] == E_SP_REGNUM
+ && operands[1] == E_SP_REGNUM
+ && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER)
+ {
+ /* Special case. We're fixing up the stack frame. */
+ uint64_t hopefully_sp
+ = (unsigned) reverse_frame[operands[1]].value;
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+ prev_sp_value = (cache->saved_regs[hopefully_sp].addr
+ - op2_as_short);
+
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value
+ = cache->saved_regs[hopefully_sp].addr;
+ trad_frame_set_value (cache->saved_regs,
+ hopefully_sp, prev_sp_value);
+ }
+ else
+ {
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
+ new_reverse_frame[i].value += op2_as_short;
+ else
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ADD:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ new_reverse_frame[i].value
+ += reverse_frame[operands[i]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVE:
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVEI:
+ case TILEGX_OPC_MOVELI:
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value = operands[1];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ORI:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have a value in A -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ = reverse_frame[operands[1]].value | operands[2];
+ }
+ else if (operands[2] == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_OR:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ }
+ else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_SUB:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ -= reverse_frame[operands[2]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+
+ case TILEGX_OPC_FNOP:
+ case TILEGX_OPC_INFO:
+ case TILEGX_OPC_INFOL:
+ /* Nothing to see here, move on.
+ Note that real NOP is treated as a 'real' instruction
+ because someone must have intended that it be there.
+ It therefore terminates the prolog.
+ */
+ break;
+
+ case TILEGX_OPC_J:
+ case TILEGX_OPC_JAL:
+
+ case TILEGX_OPC_BEQZ:
+ case TILEGX_OPC_BEQZT:
+ case TILEGX_OPC_BGEZ:
+ case TILEGX_OPC_BGEZT:
+ case TILEGX_OPC_BGTZ:
+ case TILEGX_OPC_BGTZT:
+ case TILEGX_OPC_BLBC:
+ case TILEGX_OPC_BLBCT:
+ case TILEGX_OPC_BLBS:
+ case TILEGX_OPC_BLBST:
+ case TILEGX_OPC_BLEZ:
+ case TILEGX_OPC_BLEZT:
+ case TILEGX_OPC_BLTZ:
+ case TILEGX_OPC_BLTZT:
+ case TILEGX_OPC_BNEZ:
+ case TILEGX_OPC_BNEZT:
+
+ case TILEGX_OPC_IRET:
+ case TILEGX_OPC_JALR:
+ case TILEGX_OPC_JALRP:
+ case TILEGX_OPC_JR:
+ case TILEGX_OPC_JRP:
+ case TILEGX_OPC_SWINT0:
+ case TILEGX_OPC_SWINT1:
+ case TILEGX_OPC_SWINT2:
+ case TILEGX_OPC_SWINT3:
+ /* We're really done -- this is a branch. */
+ branch_seen = 1;
+ prolog_done = 1;
+ break;
+ default:
+ /* We don't know or care what this instruction is.
+ All we know is that it isn't part of a prolog, and if
+ there's a destination register, we're trashing it. */
+ prolog_done = 1;
+ for (j = 0; j < opcode->num_operands; j++)
+ {
+ if (this_insn->operands[j]->is_dest_reg)
+ {
+ dest_regs[i] = operands[j];
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ reverse_frame_valid |= 1 << i;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now update the reverse frames. */
+ for (i = 0; i < num_insns; i++)
+ {
+ /* ISSUE: Does this properly handle "network" registers? */
+ if ((reverse_frame_valid & (1 << i))
+ && dest_regs[i] != E_ZERO_REGNUM)
+ reverse_frame[dest_regs[i]] = new_reverse_frame[i];
+ }
+
+ if (prev_sp_value != 0)
+ {
+ /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */
+ if (reverse_frame[E_R52_REGNUM].state == REVERSE_STATE_REGISTER
+ && reverse_frame[E_R52_REGNUM].value == E_SP_REGNUM)
+ {
+ reverse_frame[E_R52_REGNUM].state = REVERSE_STATE_VALUE;
+ reverse_frame[E_R52_REGNUM].value = prev_sp_value;
+ }
+
+ prev_sp_value = 0;
+ }
+
+ if (prolog_done && prolog_end == end_addr)
+ {
+ /* We found non-prolog code. As such, _this_ instruction
+ is the one after the prolog. We keep processing, because
+ there may be more prolog code in there, but this is what
+ we'll return. */
+ /* ISSUE: There may not have actually been a prologue, and
+ we may have simply skipped some random instructions. */
+ prolog_end = next_addr;
+ }
+ if (branch_seen)
+ {
+ /* We saw a branch. The prolog absolutely must be over. */
+ break;
+ }
+ }
+
+ if (prolog_end == end_addr && cache)
+ {
+ /* We may have terminated the prolog early, and we're certainly
+ at THIS point right now. It's possible that the values of
+ registers we need are currently actually in other registers
+ (and haven't been written to memory yet). Go find them. */
+ for (i = 0; i < E_NUM_PHYS_REGS; i++)
+ {
+ if (reverse_frame[i].state == REVERSE_STATE_REGISTER
+ && reverse_frame[i].value != i)
+ {
+ unsigned saved_register = (unsigned) reverse_frame[i].value;
+
+ cache->saved_regs[saved_register].realreg = i;
+ cache->saved_regs[saved_register].addr = (LONGEST) -1;
+ }
+ }
+ }
+
+ return prolog_end;
+}
+
+/* This is the implementation of gdbarch method skip_prologue. */
+
+static CORE_ADDR
+tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end && pc <= sal.end)
+ return sal.end;
+ }
+
+ /* Otherwise, try to skip prologue the hard way. */
+ return tilegx_analyze_prologue (gdbarch,
+ pc, pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES,
+ NULL, NULL);
+}
+
+/* This is the implementation of gdbarch method in_function_epilogue_p. */
+
+static int
+tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0, func_end = 0;
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ ULONGEST inst, inst2;
+ CORE_ADDR addr = func_end - TILEGX_BUNDLE_SIZE_IN_BYTES;
+
+ /* FIXME: Find the actual epilogue. */
+ /* HACK: Just assume the final bundle is the "ret" instruction". */
+ if (pc > addr)
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the implementation of gdbarch method breakpoint_from_pc. */
+
+static const unsigned char *
+tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
+{
+ /* 64-bit pattern for a { bpt ; nop } bundle. */
+ static unsigned char breakpoint[] =
+ { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+/* Normal frames. */
+
+static struct tilegx_frame_cache *
+tilegx_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct tilegx_frame_cache *cache;
+ CORE_ADDR current_pc;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct tilegx_frame_cache);
+ *this_cache = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+ cache->base = 0;
+ cache->start_pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+
+ cache->base = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
+ trad_frame_set_value (cache->saved_regs, E_SP_REGNUM, cache->base);
+
+ cache->saved_regs[E_PC_REGNUM] = cache->saved_regs[E_LR_REGNUM];
+ if (cache->start_pc)
+ tilegx_analyze_prologue (gdbarch, cache->start_pc, current_pc,
+ cache, this_frame);
+
+ return cache;
+}
+
+/* Retrieve the value of REGNUM in FRAME. */
+
+static struct value*
+tilegx_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int regnum)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs,
+ regnum);
+}
+
+/* Build frame id. */
+
+static void
+tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (info->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (info->base, info->start_pc);
+}
+
+static CORE_ADDR
+tilegx_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct tilegx_frame_cache *cache =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_unwind tilegx_frame_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ tilegx_frame_this_id,
+ tilegx_frame_prev_register,
+ NULL, /* const struct frame_data *unwind_data */
+ default_frame_sniffer, /* frame_sniffer_ftype *sniffer */
+ NULL /* frame_prev_pc_ftype *prev_pc */
+};
+
+static const struct frame_base tilegx_frame_base = {
+ &tilegx_frame_unwind,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address
+};
+
+static CORE_ADDR
+tilegx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_SP_REGNUM);
+}
+
+static CORE_ADDR
+tilegx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, E_PC_REGNUM);
+}
+
+static struct frame_id
+tilegx_unwind_dummy_id (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+
+ sp = get_frame_register_unsigned (this_frame, E_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+
+/* We cannot read/write the "special" registers. */
+
+static int
+tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno)
+{
+ if (regno >= 0 && regno < E_NUM_EASY_REGS)
+ return 0;
+ else if (regno == E_PC_REGNUM)
+ return 0;
+ else
+ return 1;
+}
+
+static struct gdbarch *
+tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ int arch_size = 64;
+
+ /* Handle arch_size == 32 or 64. Default to 64. */
+ if (info.abfd)
+ arch_size = bfd_get_arch_size (info.abfd);
+
+ if (arch_size != 32)
+ arch_size = 64;
+
+ /* Try to find a pre-existing architecture. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* We only have two flavors -- just make sure arch_size matches. */
+ if (gdbarch_ptr_bit (arches->gdbarch) == arch_size)
+ return (arches->gdbarch);
+ }
+
+ gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Basic register fields and methods, datatype sizes and stuff. */
+
+ /* There are 64 physical registers which can be referenced by
+ instructions (although only 56 of them can actually be
+ debugged) and 1 magic register (the PC). The other three
+ magic registers (ex1, syscall, orig_r0) which are known to
+ "ptrace" are ignored by "gdb". Note that we simply pretend
+ that there are 65 registers, and no "pseudo registers". */
+ set_gdbarch_num_regs (gdbarch, E_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+ set_gdbarch_sp_regnum (gdbarch, E_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, E_PC_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, tilegx_register_name);
+ set_gdbarch_register_type (gdbarch, tilegx_register_type);
+
+ set_gdbarch_char_signed (gdbarch, 0);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, arch_size);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_ptr_bit (gdbarch, arch_size);
+ set_gdbarch_addr_bit (gdbarch, arch_size);
+
+ set_gdbarch_cannot_fetch_register (gdbarch,
+ tilegx_cannot_reference_register);
+ set_gdbarch_cannot_store_register (gdbarch,
+ tilegx_cannot_reference_register);
+
+ /* Stack grows down. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Frame Info. */
+ set_gdbarch_unwind_sp (gdbarch, tilegx_unwind_sp);
+ set_gdbarch_unwind_pc (gdbarch, tilegx_unwind_pc);
+ set_gdbarch_dummy_id (gdbarch, tilegx_unwind_dummy_id);
+ set_gdbarch_frame_align (gdbarch, tilegx_frame_align);
+ frame_base_set_default (gdbarch, &tilegx_frame_base);
+
+ set_gdbarch_skip_prologue (gdbarch, tilegx_skip_prologue);
+
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ tilegx_in_function_epilogue_p);
+
+ /* Map debug registers into internal register numbers. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, tilegx_dwarf2_reg_to_regnum);
+
+ /* These values and methods are used when gdb calls a target function. */
+ set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call);
+ set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc);
+ set_gdbarch_return_value (gdbarch, tilegx_return_value);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_tilegx);
+
+ gdbarch_init_osabi (info, gdbarch);
+
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &tilegx_frame_unwind);
+
+ return gdbarch;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_tdep;
+
+void
+_initialize_tilegx_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
+}
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-24 19:26 ` Jeff Kenton
@ 2012-05-25 15:17 ` Pedro Alves
2012-05-29 15:24 ` Jeff Kenton
2012-05-29 15:24 ` [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb) Jeff Kenton
0 siblings, 2 replies; 16+ messages in thread
From: Pedro Alves @ 2012-05-25 15:17 UTC (permalink / raw)
To: Jeff Kenton; +Cc: Joel Brobecker, gdb-patches
On 05/24/2012 08:26 PM, Jeff Kenton wrote:
> On 05/23/2012 01:33 PM, Pedro Alves wrote:
>> Hi Jeff,
>>
>> On 05/21/2012 03:23 PM, Jeff Kenton wrote:
>>
>>
>
> - Comments applied.
> - SIGTRAMP frame handling improved.
> - Patch attached.
For the future, it's easier for the reviewer if you reply to the issues
and questions raised. For example, in patch 2, I'm left wondering if the
ps_get_thread_area addition fixed any testsuite failures, indicating it is
correct. I'm also left wondering what does "improved" mean
(probably fixed something in the testsuite?).
> diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
> --- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
> +++ ./gdb/tilegx-linux-tdep.c 2012-05-24 13:43:30.089276000 -0400
> +/* Supply raw registers from REGCACHE to REGS. */
> +
> +/* TILE-Gx has 56 general purpose registers,
> + plus 8 special general purpose registers (network and ZERO),
> + plus 1 magic register (PC == 64).
> + We only need the following 2 enums here. */
> +
> +enum {
> + E_NUM_EASY_REGS = 56,
> + E_PC_REGNUM = 64
> +};
> +
> +enum { tilegx_reg_size = 8 };
I didn't pay close attention to what these two enums were before. The standard thing
to do instead of defining tilegx_reg_size twice, and hacking up that short
enum for the register numbers, is to move the register numbers enum from
tilegx-tdep.c to and tilegx-tdep.h file, and include that where necessary,
so we only have one place with the register numbers.
'E_' isn't a great prefix (does it mean 'enum'?), so please replace it with
something like TILEGX_PC_REGNUM, etc. along with the move.
> +/* OS specific initialization of gdbarch. */
> +
> +static void
> +tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> + int arch_size = 64;
> +
> + /* Handle arch_size == 32 or 64. Default to 64. */
> + if (info.abfd)
> + arch_size = bfd_get_arch_size (info.abfd);
> +
> + if (arch_size != 32)
> + arch_size = 64;
Why is this 'if' necessary? Does bfd_get_arch_size ever return anything
not 32 or 64? In any case, you can just use gdbarch_addr_bit here,
as tilegx_gdbarch_init has already done the similar bfd_get_arch_size bit.
> +/* This is the implementation of gdbarch method breakpoint_from_pc. */
> +
> +static const unsigned char *
> +tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
> + CORE_ADDR *pcptr, int *lenptr)
> +{
> + /* 64-bit pattern for a { bpt ; nop } bundle. */
> + static unsigned char breakpoint[] =
static const.
> + { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
> +
> + *lenptr = sizeof (breakpoint);
> + return breakpoint;
> +}
> +
I think we're getting close. If Joel or anyone else has further comments,
the next iteration should be about ready to go in.
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-25 15:17 ` Pedro Alves
2012-05-29 15:24 ` Jeff Kenton
@ 2012-05-29 15:24 ` Jeff Kenton
2012-05-29 17:11 ` Jeff Kenton
1 sibling, 1 reply; 16+ messages in thread
From: Jeff Kenton @ 2012-05-29 15:24 UTC (permalink / raw)
To: Pedro Alves; +Cc: Joel Brobecker, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 3262 bytes --]
On 05/25/2012 11:17 AM, Pedro Alves wrote:
> On 05/24/2012 08:26 PM, Jeff Kenton wrote:
>
>> On 05/23/2012 01:33 PM, Pedro Alves wrote:
>>> Hi Jeff,
>>>
>>> On 05/21/2012 03:23 PM, Jeff Kenton wrote:
>>>
>>>
>> - Comments applied.
>> - SIGTRAMP frame handling improved.
>> - Patch attached.
>
> For the future, it's easier for the reviewer if you reply to the issues
> and questions raised. For example, in patch 2, I'm left wondering if the
> ps_get_thread_area addition fixed any testsuite failures, indicating it is
> correct. I'm also left wondering what does "improved" mean
> (probably fixed something in the testsuite?).
ps_get_thread_area didn't affect the testsuite results.
SIGTRAMP_FRAME improvements eliminated 65 FAILs in the sigstep tests (48
still FAIL -- I'm working on those).
>
>> diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
>> --- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
>> +++ ./gdb/tilegx-linux-tdep.c 2012-05-24 13:43:30.089276000 -0400
>> +/* Supply raw registers from REGCACHE to REGS. */
>> +
>> +/* TILE-Gx has 56 general purpose registers,
>> + plus 8 special general purpose registers (network and ZERO),
>> + plus 1 magic register (PC == 64).
>> + We only need the following 2 enums here. */
>> +
>> +enum {
>> + E_NUM_EASY_REGS = 56,
>> + E_PC_REGNUM = 64
>> +};
>> +
>> +enum { tilegx_reg_size = 8 };
>
>
> I didn't pay close attention to what these two enums were before. The standard thing
> to do instead of defining tilegx_reg_size twice, and hacking up that short
> enum for the register numbers, is to move the register numbers enum from
> tilegx-tdep.c to and tilegx-tdep.h file, and include that where necessary,
> so we only have one place with the register numbers.
> 'E_' isn't a great prefix (does it mean 'enum'?), so please replace it with
> something like TILEGX_PC_REGNUM, etc. along with the move.
Done. Good suggestion.
>
>> +/* OS specific initialization of gdbarch. */
>> +
>> +static void
>> +tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>> +{
>> + int arch_size = 64;
>> +
>> + /* Handle arch_size == 32 or 64. Default to 64. */
>> + if (info.abfd)
>> + arch_size = bfd_get_arch_size (info.abfd);
>> +
>> + if (arch_size != 32)
>> + arch_size = 64;
>
> Why is this 'if' necessary? Does bfd_get_arch_size ever return anything
> not 32 or 64? In any case, you can just use gdbarch_addr_bit here,
> as tilegx_gdbarch_init has already done the similar bfd_get_arch_size bit.
Done.
>
>
>
>> +/* This is the implementation of gdbarch method breakpoint_from_pc. */
>> +
>> +static const unsigned char *
>> +tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
>> + CORE_ADDR *pcptr, int *lenptr)
>> +{
>> + /* 64-bit pattern for a { bpt ; nop } bundle. */
>> + static unsigned char breakpoint[] =
>
> static const.
Done.
>
>> + { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
>> +
>> + *lenptr = sizeof (breakpoint);
>> + return breakpoint;
>> +}
>> +
> I think we're getting close. If Joel or anyone else has further comments,
> the next iteration should be about ready to go in.
>
Thanks.
--jeff kenton
[-- Attachment #2: patch_1 --]
[-- Type: text/plain, Size: 47911 bytes --]
gdb/
* Makefile.in (ALL_TARGET_OBJS): Add tilegx-tdep.o, tilegx-linux-tdep.o.
(ALLDEPFILES): tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c.
* configure.tgt: Add tilegx target.
* tilegx-tdep.h: New file.
* tilegx-tdep.c: New file.
* tilegx-linux-tdep.c: New file.
* regformats/reg-tilegx.dat: New file.
diff -r -u -N /home/packages/gdb-7.4x/gdb/configure.tgt ./gdb/configure.tgt
--- /home/packages/gdb-7.4x/gdb/configure.tgt 2012-03-05 06:41:51.000000000 -0500
+++ ./gdb/configure.tgt 2012-05-29 09:35:10.055133000 -0400
@@ -551,6 +551,13 @@
gdb_target_obs="tic6x-tdep.o"
;;
+tilegx-*-linux*)
+ # Target: TILE-Gx
+ gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
+ symfile-mem.o glibc-tdep.o linux-tdep.o"
+ ;;
+
+
xstormy16-*-*)
# Target: Sanyo Xstormy16a processor
gdb_target_obs="xstormy16-tdep.o"
diff -r -u -N /home/packages/gdb-7.4x/gdb/Makefile.in ./gdb/Makefile.in
--- /home/packages/gdb-7.4x/gdb/Makefile.in 2012-03-28 17:31:18.000000000 -0400
+++ ./gdb/Makefile.in 2012-05-29 09:35:09.951137000 -0400
@@ -565,6 +565,7 @@
sparc-sol2-tdep.o sparc-tdep.o \
spu-tdep.o spu-multiarch.o solib-spu.o \
tic6x-tdep.o tic6x-linux-tdep.o \
+ tilegx-tdep.o tilegx-linux-tdep.o \
v850-tdep.o \
vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
xstormy16-tdep.o \
@@ -1510,6 +1511,7 @@
sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
+ tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c \
v850-tdep.c \
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
windows-nat.c windows-tdep.c \
diff -r -u -N /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat ./gdb/regformats/reg-tilegx.dat
--- /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/regformats/reg-tilegx.dat 2012-05-29 09:35:10.182128000 -0400
@@ -0,0 +1,67 @@
+name:tile
+expedite:sp,lr,pc
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:r32
+64:r33
+64:r34
+64:r35
+64:r36
+64:r37
+64:r38
+64:r39
+64:r40
+64:r41
+64:r42
+64:r43
+64:r44
+64:r45
+64:r46
+64:r47
+64:r48
+64:r49
+64:r50
+64:r51
+64:r52
+64:tp
+64:sp
+64:lr
+64:sn
+64:io0
+64:io1
+64:us0
+64:us1
+64:us2
+64:us3
+64:zero
+64:pc
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-linux-tdep.c 2012-05-29 09:35:10.225123000 -0400
@@ -0,0 +1,148 @@
+/* Target-dependent code for GNU/Linux on Xtensa processors.
+
+ Copyright 2012 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 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 "osabi.h"
+#include "linux-tdep.h"
+#include "glibc-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "regcache.h"
+#include "regset.h"
+#include "tramp-frame.h"
+#include "trad-frame.h"
+
+#include "tilegx-tdep.h"
+
+/* Signal trampoline support. */
+
+static void
+tilegx_linux_sigframe_init (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ CORE_ADDR pc = get_frame_register_unsigned (this_frame, 64);
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, 54);
+ CORE_ADDR base = sp + 16;
+ int i;
+
+ for (i = 0; i < 56; i++)
+ trad_frame_set_reg_addr (this_cache, i, base + i * 8);
+
+ trad_frame_set_reg_value (this_cache, 64, pc);
+
+ /* Save a frame ID. */
+ trad_frame_set_id (this_cache, frame_id_build (base, func));
+}
+
+static const struct tramp_frame tilegx_linux_rt_sigframe =
+{
+ SIGTRAMP_FRAME,
+ 8,
+ {
+ { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
+ { 0x286b180051485000, -1 }, /* { swint1 } */
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ tilegx_linux_sigframe_init
+};
+
+/* Supply raw registers from REGCACHE to REGS. */
+
+static void
+tilegx_linux_supply_regset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *regs, size_t len)
+{
+ struct gdbarch *arch = get_regcache_arch (regcache);
+ const char *ptr = regs;
+ int i;
+
+ /* This logic must match that of struct pt_regs in "ptrace.h". */
+ for (i = 0; i < TILEGX_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size)
+ {
+ int gri = (i < TILEGX_NUM_EASY_REGS) ? i : TILEGX_PC_REGNUM;
+
+ if (regnum == gri || regnum == -1)
+ regcache_raw_supply (regcache, gri, ptr);
+ }
+}
+
+
+/* TILE-Gx Linux kernel register set. */
+static struct regset tilegx_linux_regset =
+{
+ NULL,
+ tilegx_linux_supply_regset
+};
+
+static const struct regset *
+tilegx_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ if (strcmp (sect_name, ".reg") == 0)
+ return &tilegx_linux_regset;
+
+ return NULL;
+}
+
+/* OS specific initialization of gdbarch. */
+
+static void
+tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ int arch_size = gdbarch_addr_bit (gdbarch);
+
+ linux_init_abi (info, gdbarch);
+
+ tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
+
+ set_gdbarch_regset_from_core_section (gdbarch,
+ tilegx_regset_from_core_section);
+
+ /* GNU/Linux uses SVR4-style shared libraries. */
+ if (arch_size == 32)
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+ else
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
+
+ /* Shared library handling. */
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_linux_tdep;
+
+void
+_initialize_tilegx_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_tilegx, bfd_mach_tilegx, GDB_OSABI_LINUX,
+ tilegx_linux_init_abi);
+}
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.c 2012-05-29 09:35:10.070125000 -0400
@@ -0,0 +1,1023 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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 "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "dis-asm.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "regset.h"
+#include "doublest.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "objfiles.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+
+#include "tilegx-tdep.h"
+
+#include "opcode/tilegx.h"
+
+struct tilegx_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ /* Function start. */
+ CORE_ADDR start_pc;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Register state values used by analyze_prologue. */
+enum reverse_state {
+ REVERSE_STATE_REGISTER,
+ REVERSE_STATE_VALUE,
+ REVERSE_STATE_UNKNOWN
+};
+
+/* Register state used by analyze_prologue(). */
+struct tilegx_reverse_regs
+{
+ LONGEST value;
+ enum reverse_state state;
+};
+
+static const struct tilegx_reverse_regs
+template_reverse_regs[TILEGX_NUM_PHYS_REGS] =
+ {
+ { TILEGX_R0_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R1_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R2_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R3_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R4_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R5_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R6_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R7_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R8_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R9_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R10_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R11_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R12_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R13_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R14_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R15_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R16_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R17_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R18_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R19_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R20_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R21_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R22_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R23_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R24_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R25_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R26_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R27_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R28_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R29_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R30_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R31_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R32_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R33_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R34_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R35_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R36_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R37_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R38_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R39_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R40_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R41_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R42_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R43_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R44_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R45_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R46_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R47_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R48_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R49_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R50_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R51_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R52_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_TP_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_SP_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_LR_REGNUM, REVERSE_STATE_REGISTER },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { TILEGX_ZERO_REGNUM, REVERSE_STATE_VALUE }
+ };
+
+/* Implement the "register_name" gdbarch method. */
+
+static const char *
+tilegx_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ static const char *const register_names[TILEGX_NUM_REGS] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr",
+ "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero",
+ "pc"
+ };
+
+ if (regnum < 0 || regnum >= TILEGX_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "tilegx_register_name: illegal register number %d",
+ regnum);
+
+ return register_names[regnum];
+}
+
+/* This is the implementation of gdbarch method register_type. */
+
+static struct type *
+tilegx_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == TILEGX_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+}
+
+/* This is the implementation of gdbarch method dwarf2_reg_to_regnum. */
+
+static int
+tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ return num;
+}
+
+
+/* Makes the decision if a given type is a scalar type. Scalar
+ types are returned in the registers r2-r11 as they fit. */
+
+static int
+tilegx_type_is_scalar (struct type *t)
+{
+ return (TYPE_CODE(t) != TYPE_CODE_STRUCT
+ && TYPE_CODE(t) != TYPE_CODE_UNION
+ && TYPE_CODE(t) != TYPE_CODE_ARRAY);
+}
+
+/* Returns non-zero if the given struct type will be returned using
+ a special convention, rather than the normal function return method.
+ Used in the context of the "return" command, and target function
+ calls from the debugger. */
+
+static int
+tilegx_use_struct_convention (struct type *type)
+{
+ /* Only scalars which fit in R0 - R9 can be returned in registers.
+ Otherwise, they are returned via a pointer passed in R0. */
+ return !tilegx_type_is_scalar (type)
+ && (TYPE_LENGTH (type) > (1 + TILEGX_R9_REGNUM - TILEGX_R0_REGNUM)
+ * tilegx_reg_size);
+}
+
+/* Find a function's return value in the appropriate registers (in
+ regbuf), and copy it into valbuf. */
+
+static void
+tilegx_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ int i, regnum = TILEGX_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_read (regcache, regnum++, valbuf + i);
+}
+
+/* Copy the function return value from VALBUF into the proper
+ location for a function return.
+ Called only in the context of the "return" command. */
+
+static void
+tilegx_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ if (TYPE_LENGTH (type) < tilegx_reg_size)
+ {
+ /* Add leading zeros to the (little-endian) value. */
+ gdb_byte buf[tilegx_reg_size] = { 0 };
+
+ memcpy (buf, valbuf, TYPE_LENGTH (type));
+ regcache_raw_write (regcache, TILEGX_R0_REGNUM, buf);
+ }
+ else
+ {
+ int len = TYPE_LENGTH (type);
+ int i, regnum = TILEGX_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_write (regcache, regnum++, (gdb_byte *) valbuf + i);
+ }
+}
+
+/* This is the implementation of gdbarch method return_value. */
+
+static enum return_value_convention
+tilegx_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (tilegx_use_struct_convention (type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ if (writebuf)
+ tilegx_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ tilegx_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* This is the implementation of gdbarch method frame_align. */
+
+static CORE_ADDR
+tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return addr & -8;
+}
+
+
+/* Implement the "push_dummy_call" gdbarch method. */
+
+static CORE_ADDR
+tilegx_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);
+ CORE_ADDR stack_dest = sp;
+ int argreg = TILEGX_R0_REGNUM;
+ int i, j;
+ int typelen, slacklen, alignlen;
+ static const gdb_byte two_zero_words[8] = { 0 };
+
+ /* If struct_return is 1, then the struct return address will
+ consume one argument-passing register. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
+
+ /* Arguments are passed in R0 - R9, and as soon as an argument
+ will not fit completely in the remaining registers, then it,
+ and all remaining arguments, are put on the stack. */
+ for (i = 0; i < nargs && argreg <= TILEGX_R9_REGNUM; i++)
+ {
+ const gdb_byte *val;
+ typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
+
+ if (typelen > (TILEGX_R9_REGNUM - argreg + 1) * tilegx_reg_size)
+ break;
+
+ /* Put argument into registers wordwise. */
+ val = value_contents (args[i]);
+ for (j = 0; j < typelen; j += tilegx_reg_size)
+ {
+ /* ISSUE: Why special handling for "typelen = 4x + 1"?
+ I don't ever see "typelen" values except 4 and 8. */
+ int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
+ ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
+
+ regcache_cooked_write_unsigned (regcache, argreg++, w);
+ }
+ }
+
+ /* Align SP. */
+ stack_dest = tilegx_frame_align (gdbarch, stack_dest);
+
+ /* Loop backwards through arguments to determine stack alignment. */
+ alignlen = 0;
+
+ for (j = nargs - 1; j >= i; j--)
+ {
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ alignlen += (typelen + 3) & (~3);
+ }
+
+ if (alignlen & 0x4)
+ stack_dest -= 4;
+
+ /* Loop backwards through remaining arguments and push them on
+ the stack, word aligned. */
+ for (j = nargs - 1; j >= i; j--)
+ {
+ gdb_byte *val;
+
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ slacklen = ((typelen + 3) & (~3)) - typelen;
+ val = alloca (typelen + slacklen);
+ memcpy (val, value_contents (args[j]), typelen);
+ memset (val + typelen, 0, slacklen);
+
+ /* Now write data to the stack. The stack grows downwards. */
+ stack_dest -= typelen + slacklen;
+ write_memory (stack_dest, val, typelen + slacklen);
+ }
+
+ /* Add 2 words for linkage space to the stack. */
+ stack_dest = stack_dest - 8;
+ write_memory (stack_dest, two_zero_words, 8);
+
+ /* Update stack pointer. */
+ regcache_cooked_write_unsigned (regcache, TILEGX_SP_REGNUM, stack_dest);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_unsigned (regcache, TILEGX_LR_REGNUM, bp_addr);
+
+ return stack_dest;
+}
+
+
+/* Decode the instructions within the given address range.
+ Decide when we must have reached the end of the function prologue.
+ If a frame_info pointer is provided, fill in its saved_regs etc.
+ Returns the address of the first instruction after the prologue.
+ NOTE: This is often called with start_addr being the start of some
+ function, and end_addr being the current PC. */
+
+static CORE_ADDR
+tilegx_analyze_prologue (struct gdbarch* gdbarch,
+ CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct tilegx_frame_cache *cache,
+ struct frame_info *next_frame)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR next_addr;
+ CORE_ADDR prolog_end = end_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+ gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
+ CORE_ADDR instbuf_start;
+ unsigned int instbuf_size;
+ int status;
+ bfd_uint64_t bundle;
+ struct tilegx_decoded_instruction
+ decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int num_insns;
+ struct tilegx_reverse_regs reverse_frame[TILEGX_NUM_PHYS_REGS];
+ struct tilegx_reverse_regs
+ new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int reverse_frame_valid, prolog_done, branch_seen;
+ LONGEST prev_sp_value;
+ int i, j;
+
+ if (start_addr >= end_addr
+ || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
+ return end_addr;
+
+ /* Initialize the reverse frame. This maps the CURRENT frame's
+ registers to the outer frame's registers (the frame on the
+ stack goes the other way). */
+ memcpy (&reverse_frame, &template_reverse_regs,
+ sizeof (reverse_frame));
+
+ prolog_done = 0;
+ branch_seen = 0;
+ prev_sp_value = 0;
+
+ /* To cut down on round-trip overhead, we fetch multiple bundles
+ at once. These variables describe the range of memory we have
+ prefetched. */
+ instbuf_start = 0;
+ instbuf_size = 0;
+
+ for (next_addr = start_addr; next_addr < end_addr;
+ next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
+ {
+ /* Retrieve the next instruction. */
+ if (next_addr - instbuf_start >= instbuf_size)
+ {
+ /* Figure out how many bytes to fetch. Don't span a page
+ boundary since that might cause an unnecessary memory
+ error. */
+ unsigned int size_on_same_page = 4096 - (next_addr & 4095);
+ instbuf_size = sizeof instbuf;
+
+ if (instbuf_size > size_on_same_page)
+ instbuf_size = size_on_same_page;
+ instbuf_start = next_addr;
+
+ status = safe_frame_unwind_memory (next_frame, instbuf_start,
+ instbuf, instbuf_size);
+ if (status == 0)
+ memory_error (status, next_addr);
+ }
+
+ reverse_frame_valid = 0;
+
+ bundle = extract_unsigned_integer (&instbuf[next_addr
+ - instbuf_start],
+ 8, byte_order);
+
+ num_insns = parse_insn_tilegx (bundle, next_addr, decoded);
+
+ for (i = 0; i < num_insns; i++)
+ {
+ struct tilegx_decoded_instruction *this_insn = &decoded[i];
+ int64_t *operands = (int64_t *) this_insn->operand_values;
+ const struct tilegx_opcode *opcode = this_insn->opcode;
+
+ switch (opcode->mnemonic)
+ {
+ case TILEGX_OPC_ST:
+ if (cache
+ && reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].state
+ == REVERSE_STATE_REGISTER)
+ {
+ LONGEST saved_address = reverse_frame[operands[0]].value;
+ unsigned saved_register
+ = (unsigned) reverse_frame[operands[1]].value;
+
+ /* realreg >= 0 and addr != -1 indicates that the
+ value of saved_register is in memory location
+ saved_address. The value of realreg is not
+ meaningful in this case but it must be >= 0.
+ See trad-frame.h. */
+ cache->saved_regs[saved_register].realreg = saved_register;
+ cache->saved_regs[saved_register].addr = saved_address;
+ }
+ break;
+ case TILEGX_OPC_ADDI:
+ case TILEGX_OPC_ADDLI:
+ if (cache
+ && operands[0] == TILEGX_SP_REGNUM
+ && operands[1] == TILEGX_SP_REGNUM
+ && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER)
+ {
+ /* Special case. We're fixing up the stack frame. */
+ uint64_t hopefully_sp
+ = (unsigned) reverse_frame[operands[1]].value;
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+ prev_sp_value = (cache->saved_regs[hopefully_sp].addr
+ - op2_as_short);
+
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value
+ = cache->saved_regs[hopefully_sp].addr;
+ trad_frame_set_value (cache->saved_regs,
+ hopefully_sp, prev_sp_value);
+ }
+ else
+ {
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
+ new_reverse_frame[i].value += op2_as_short;
+ else
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ADD:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ new_reverse_frame[i].value
+ += reverse_frame[operands[i]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVE:
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVEI:
+ case TILEGX_OPC_MOVELI:
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value = operands[1];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ORI:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have a value in A -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ = reverse_frame[operands[1]].value | operands[2];
+ }
+ else if (operands[2] == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_OR:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ }
+ else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_SUB:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ -= reverse_frame[operands[2]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+
+ case TILEGX_OPC_FNOP:
+ case TILEGX_OPC_INFO:
+ case TILEGX_OPC_INFOL:
+ /* Nothing to see here, move on.
+ Note that real NOP is treated as a 'real' instruction
+ because someone must have intended that it be there.
+ It therefore terminates the prolog.
+ */
+ break;
+
+ case TILEGX_OPC_J:
+ case TILEGX_OPC_JAL:
+
+ case TILEGX_OPC_BEQZ:
+ case TILEGX_OPC_BEQZT:
+ case TILEGX_OPC_BGEZ:
+ case TILEGX_OPC_BGEZT:
+ case TILEGX_OPC_BGTZ:
+ case TILEGX_OPC_BGTZT:
+ case TILEGX_OPC_BLBC:
+ case TILEGX_OPC_BLBCT:
+ case TILEGX_OPC_BLBS:
+ case TILEGX_OPC_BLBST:
+ case TILEGX_OPC_BLEZ:
+ case TILEGX_OPC_BLEZT:
+ case TILEGX_OPC_BLTZ:
+ case TILEGX_OPC_BLTZT:
+ case TILEGX_OPC_BNEZ:
+ case TILEGX_OPC_BNEZT:
+
+ case TILEGX_OPC_IRET:
+ case TILEGX_OPC_JALR:
+ case TILEGX_OPC_JALRP:
+ case TILEGX_OPC_JR:
+ case TILEGX_OPC_JRP:
+ case TILEGX_OPC_SWINT0:
+ case TILEGX_OPC_SWINT1:
+ case TILEGX_OPC_SWINT2:
+ case TILEGX_OPC_SWINT3:
+ /* We're really done -- this is a branch. */
+ branch_seen = 1;
+ prolog_done = 1;
+ break;
+ default:
+ /* We don't know or care what this instruction is.
+ All we know is that it isn't part of a prolog, and if
+ there's a destination register, we're trashing it. */
+ prolog_done = 1;
+ for (j = 0; j < opcode->num_operands; j++)
+ {
+ if (this_insn->operands[j]->is_dest_reg)
+ {
+ dest_regs[i] = operands[j];
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ reverse_frame_valid |= 1 << i;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now update the reverse frames. */
+ for (i = 0; i < num_insns; i++)
+ {
+ /* ISSUE: Does this properly handle "network" registers? */
+ if ((reverse_frame_valid & (1 << i))
+ && dest_regs[i] != TILEGX_ZERO_REGNUM)
+ reverse_frame[dest_regs[i]] = new_reverse_frame[i];
+ }
+
+ if (prev_sp_value != 0)
+ {
+ /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */
+ if (reverse_frame[TILEGX_R52_REGNUM].state == REVERSE_STATE_REGISTER
+ && reverse_frame[TILEGX_R52_REGNUM].value == TILEGX_SP_REGNUM)
+ {
+ reverse_frame[TILEGX_R52_REGNUM].state = REVERSE_STATE_VALUE;
+ reverse_frame[TILEGX_R52_REGNUM].value = prev_sp_value;
+ }
+
+ prev_sp_value = 0;
+ }
+
+ if (prolog_done && prolog_end == end_addr)
+ {
+ /* We found non-prolog code. As such, _this_ instruction
+ is the one after the prolog. We keep processing, because
+ there may be more prolog code in there, but this is what
+ we'll return. */
+ /* ISSUE: There may not have actually been a prologue, and
+ we may have simply skipped some random instructions. */
+ prolog_end = next_addr;
+ }
+ if (branch_seen)
+ {
+ /* We saw a branch. The prolog absolutely must be over. */
+ break;
+ }
+ }
+
+ if (prolog_end == end_addr && cache)
+ {
+ /* We may have terminated the prolog early, and we're certainly
+ at THIS point right now. It's possible that the values of
+ registers we need are currently actually in other registers
+ (and haven't been written to memory yet). Go find them. */
+ for (i = 0; i < TILEGX_NUM_PHYS_REGS; i++)
+ {
+ if (reverse_frame[i].state == REVERSE_STATE_REGISTER
+ && reverse_frame[i].value != i)
+ {
+ unsigned saved_register = (unsigned) reverse_frame[i].value;
+
+ cache->saved_regs[saved_register].realreg = i;
+ cache->saved_regs[saved_register].addr = (LONGEST) -1;
+ }
+ }
+ }
+
+ return prolog_end;
+}
+
+/* This is the implementation of gdbarch method skip_prologue. */
+
+static CORE_ADDR
+tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end && pc <= sal.end)
+ return sal.end;
+ }
+
+ /* Otherwise, try to skip prologue the hard way. */
+ return tilegx_analyze_prologue (gdbarch,
+ pc, pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES,
+ NULL, NULL);
+}
+
+/* This is the implementation of gdbarch method in_function_epilogue_p. */
+
+static int
+tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0, func_end = 0;
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ ULONGEST inst, inst2;
+ CORE_ADDR addr = func_end - TILEGX_BUNDLE_SIZE_IN_BYTES;
+
+ /* FIXME: Find the actual epilogue. */
+ /* HACK: Just assume the final bundle is the "ret" instruction". */
+ if (pc > addr)
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the implementation of gdbarch method breakpoint_from_pc. */
+
+static const unsigned char *
+tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
+{
+ /* 64-bit pattern for a { bpt ; nop } bundle. */
+ static const unsigned char breakpoint[] =
+ { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+/* Normal frames. */
+
+static struct tilegx_frame_cache *
+tilegx_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct tilegx_frame_cache *cache;
+ CORE_ADDR current_pc;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct tilegx_frame_cache);
+ *this_cache = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+ cache->base = 0;
+ cache->start_pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+
+ cache->base = get_frame_register_unsigned (this_frame, TILEGX_SP_REGNUM);
+ trad_frame_set_value (cache->saved_regs, TILEGX_SP_REGNUM, cache->base);
+
+ cache->saved_regs[TILEGX_PC_REGNUM] = cache->saved_regs[TILEGX_LR_REGNUM];
+ if (cache->start_pc)
+ tilegx_analyze_prologue (gdbarch, cache->start_pc, current_pc,
+ cache, this_frame);
+
+ return cache;
+}
+
+/* Retrieve the value of REGNUM in FRAME. */
+
+static struct value*
+tilegx_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int regnum)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs,
+ regnum);
+}
+
+/* Build frame id. */
+
+static void
+tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (info->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (info->base, info->start_pc);
+}
+
+static CORE_ADDR
+tilegx_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct tilegx_frame_cache *cache =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_unwind tilegx_frame_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ tilegx_frame_this_id,
+ tilegx_frame_prev_register,
+ NULL, /* const struct frame_data *unwind_data */
+ default_frame_sniffer, /* frame_sniffer_ftype *sniffer */
+ NULL /* frame_prev_pc_ftype *prev_pc */
+};
+
+static const struct frame_base tilegx_frame_base = {
+ &tilegx_frame_unwind,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address
+};
+
+static CORE_ADDR
+tilegx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, TILEGX_SP_REGNUM);
+}
+
+static CORE_ADDR
+tilegx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, TILEGX_PC_REGNUM);
+}
+
+static struct frame_id
+tilegx_unwind_dummy_id (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+
+ sp = get_frame_register_unsigned (this_frame, TILEGX_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+
+/* We cannot read/write the "special" registers. */
+
+static int
+tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno)
+{
+ if (regno >= 0 && regno < TILEGX_NUM_EASY_REGS)
+ return 0;
+ else if (regno == TILEGX_PC_REGNUM)
+ return 0;
+ else
+ return 1;
+}
+
+static struct gdbarch *
+tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ int arch_size = 64;
+
+ /* Handle arch_size == 32 or 64. Default to 64. */
+ if (info.abfd)
+ arch_size = bfd_get_arch_size (info.abfd);
+
+ if (arch_size != 32)
+ arch_size = 64;
+
+ /* Try to find a pre-existing architecture. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* We only have two flavors -- just make sure arch_size matches. */
+ if (gdbarch_ptr_bit (arches->gdbarch) == arch_size)
+ return (arches->gdbarch);
+ }
+
+ gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Basic register fields and methods, datatype sizes and stuff. */
+
+ /* There are 64 physical registers which can be referenced by
+ instructions (although only 56 of them can actually be
+ debugged) and 1 magic register (the PC). The other three
+ magic registers (ex1, syscall, orig_r0) which are known to
+ "ptrace" are ignored by "gdb". Note that we simply pretend
+ that there are 65 registers, and no "pseudo registers". */
+ set_gdbarch_num_regs (gdbarch, TILEGX_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+ set_gdbarch_sp_regnum (gdbarch, TILEGX_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, TILEGX_PC_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, tilegx_register_name);
+ set_gdbarch_register_type (gdbarch, tilegx_register_type);
+
+ set_gdbarch_char_signed (gdbarch, 0);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, arch_size);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_ptr_bit (gdbarch, arch_size);
+ set_gdbarch_addr_bit (gdbarch, arch_size);
+
+ set_gdbarch_cannot_fetch_register (gdbarch,
+ tilegx_cannot_reference_register);
+ set_gdbarch_cannot_store_register (gdbarch,
+ tilegx_cannot_reference_register);
+
+ /* Stack grows down. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Frame Info. */
+ set_gdbarch_unwind_sp (gdbarch, tilegx_unwind_sp);
+ set_gdbarch_unwind_pc (gdbarch, tilegx_unwind_pc);
+ set_gdbarch_dummy_id (gdbarch, tilegx_unwind_dummy_id);
+ set_gdbarch_frame_align (gdbarch, tilegx_frame_align);
+ frame_base_set_default (gdbarch, &tilegx_frame_base);
+
+ set_gdbarch_skip_prologue (gdbarch, tilegx_skip_prologue);
+
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ tilegx_in_function_epilogue_p);
+
+ /* Map debug registers into internal register numbers. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, tilegx_dwarf2_reg_to_regnum);
+
+ /* These values and methods are used when gdb calls a target function. */
+ set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call);
+ set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc);
+ set_gdbarch_return_value (gdbarch, tilegx_return_value);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_tilegx);
+
+ gdbarch_init_osabi (info, gdbarch);
+
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &tilegx_frame_unwind);
+
+ return gdbarch;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_tdep;
+
+void
+_initialize_tilegx_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
+}
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.h ./gdb/tilegx-tdep.h
--- /home/packages/gdb-7.4x/gdb/tilegx-tdep.h 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.h 2012-05-29 09:35:10.206128000 -0400
@@ -0,0 +1,103 @@
+
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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/>. */
+
+
+/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
+ plus 8 special general purpose registers (network and ZERO),
+ plus 1 magic register (PC).
+
+ TP (aka R53) is the thread specific data pointer.
+ SP (aka R54) is the stack pointer.
+ LR (aka R55) is the link register.
+ */
+enum {
+ TILEGX_R0_REGNUM,
+ TILEGX_R1_REGNUM,
+ TILEGX_R2_REGNUM,
+ TILEGX_R3_REGNUM,
+ TILEGX_R4_REGNUM,
+ TILEGX_R5_REGNUM,
+ TILEGX_R6_REGNUM,
+ TILEGX_R7_REGNUM,
+ TILEGX_R8_REGNUM,
+ TILEGX_R9_REGNUM,
+ TILEGX_R10_REGNUM,
+ TILEGX_R11_REGNUM,
+ TILEGX_R12_REGNUM,
+ TILEGX_R13_REGNUM,
+ TILEGX_R14_REGNUM,
+ TILEGX_R15_REGNUM,
+ TILEGX_R16_REGNUM,
+ TILEGX_R17_REGNUM,
+ TILEGX_R18_REGNUM,
+ TILEGX_R19_REGNUM,
+ TILEGX_R20_REGNUM,
+ TILEGX_R21_REGNUM,
+ TILEGX_R22_REGNUM,
+ TILEGX_R23_REGNUM,
+ TILEGX_R24_REGNUM,
+ TILEGX_R25_REGNUM,
+ TILEGX_R26_REGNUM,
+ TILEGX_R27_REGNUM,
+ TILEGX_R28_REGNUM,
+ TILEGX_R29_REGNUM,
+ TILEGX_R30_REGNUM,
+ TILEGX_R31_REGNUM,
+ TILEGX_R32_REGNUM,
+ TILEGX_R33_REGNUM,
+ TILEGX_R34_REGNUM,
+ TILEGX_R35_REGNUM,
+ TILEGX_R36_REGNUM,
+ TILEGX_R37_REGNUM,
+ TILEGX_R38_REGNUM,
+ TILEGX_R39_REGNUM,
+ TILEGX_R40_REGNUM,
+ TILEGX_R41_REGNUM,
+ TILEGX_R42_REGNUM,
+ TILEGX_R43_REGNUM,
+ TILEGX_R44_REGNUM,
+ TILEGX_R45_REGNUM,
+ TILEGX_R46_REGNUM,
+ TILEGX_R47_REGNUM,
+ TILEGX_R48_REGNUM,
+ TILEGX_R49_REGNUM,
+ TILEGX_R50_REGNUM,
+ TILEGX_R51_REGNUM,
+ TILEGX_R52_REGNUM,
+ TILEGX_TP_REGNUM,
+ TILEGX_SP_REGNUM,
+ TILEGX_LR_REGNUM,
+
+ TILEGX_SN_REGNUM, TILEGX_NUM_EASY_REGS = TILEGX_SN_REGNUM, /* 56 */
+ TILEGX_IO0_REGNUM,
+ TILEGX_IO1_REGNUM,
+ TILEGX_US0_REGNUM,
+ TILEGX_US1_REGNUM,
+ TILEGX_US2_REGNUM,
+ TILEGX_US3_REGNUM,
+ TILEGX_ZERO_REGNUM,
+
+ TILEGX_PC_REGNUM, TILEGX_NUM_PHYS_REGS = TILEGX_PC_REGNUM, /* 64 */
+
+ TILEGX_NUM_REGS /* 65 */
+};
+
+enum { tilegx_reg_size = 8 };
+
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-25 15:17 ` Pedro Alves
@ 2012-05-29 15:24 ` Jeff Kenton
2012-05-30 19:56 ` Pedro Alves
2012-05-29 15:24 ` [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb) Jeff Kenton
1 sibling, 1 reply; 16+ messages in thread
From: Jeff Kenton @ 2012-05-29 15:24 UTC (permalink / raw)
To: Pedro Alves; +Cc: Joel Brobecker, gdb-patches
[-- Attachment #1: Type: text/plain, Size: 3287 bytes --]
On 05/25/2012 11:17 AM, Pedro Alves wrote:
> On 05/24/2012 08:26 PM, Jeff Kenton wrote:
>
>> On 05/23/2012 01:33 PM, Pedro Alves wrote:
>>> Hi Jeff,
>>>
>>> On 05/21/2012 03:23 PM, Jeff Kenton wrote:
>>>
>>>
>> - Comments applied.
>> - SIGTRAMP frame handling improved.
>> - Patch attached.
>
> For the future, it's easier for the reviewer if you reply to the issues
> and questions raised. For example, in patch 2, I'm left wondering if the
> ps_get_thread_area addition fixed any testsuite failures, indicating it is
> correct. I'm also left wondering what does "improved" mean
> (probably fixed something in the testsuite?).
ps_get_thread_area didn't affect the testsuite results.
SIGTRAMP_FRAME improvements eliminated 65 FAILs in the sigstep tests (48
still FAIL -- I'm working on those).
>
>> diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
>> --- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
>> +++ ./gdb/tilegx-linux-tdep.c 2012-05-24 13:43:30.089276000 -0400
>> +/* Supply raw registers from REGCACHE to REGS. */
>> +
>> +/* TILE-Gx has 56 general purpose registers,
>> + plus 8 special general purpose registers (network and ZERO),
>> + plus 1 magic register (PC == 64).
>> + We only need the following 2 enums here. */
>> +
>> +enum {
>> + E_NUM_EASY_REGS = 56,
>> + E_PC_REGNUM = 64
>> +};
>> +
>> +enum { tilegx_reg_size = 8 };
>
>
> I didn't pay close attention to what these two enums were before. The standard thing
> to do instead of defining tilegx_reg_size twice, and hacking up that short
> enum for the register numbers, is to move the register numbers enum from
> tilegx-tdep.c to and tilegx-tdep.h file, and include that where necessary,
> so we only have one place with the register numbers.
> 'E_' isn't a great prefix (does it mean 'enum'?), so please replace it with
> something like TILEGX_PC_REGNUM, etc. along with the move.
Done. Good suggestion.
>
>> +/* OS specific initialization of gdbarch. */
>> +
>> +static void
>> +tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>> +{
>> + int arch_size = 64;
>> +
>> + /* Handle arch_size == 32 or 64. Default to 64. */
>> + if (info.abfd)
>> + arch_size = bfd_get_arch_size (info.abfd);
>> +
>> + if (arch_size != 32)
>> + arch_size = 64;
>
> Why is this 'if' necessary? Does bfd_get_arch_size ever return anything
> not 32 or 64? In any case, you can just use gdbarch_addr_bit here,
> as tilegx_gdbarch_init has already done the similar bfd_get_arch_size bit.
Done.
>
>
>
>> +/* This is the implementation of gdbarch method breakpoint_from_pc. */
>> +
>> +static const unsigned char *
>> +tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
>> + CORE_ADDR *pcptr, int *lenptr)
>> +{
>> + /* 64-bit pattern for a { bpt ; nop } bundle. */
>> + static unsigned char breakpoint[] =
>
> static const.
Done.
>
>> + { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
>> +
>> + *lenptr = sizeof (breakpoint);
>> + return breakpoint;
>> +}
>> +
> I think we're getting close. If Joel or anyone else has further comments,
> the next iteration should be about ready to go in.
>
Updated patch attached.
Thanks.
--jeff kenton
[-- Attachment #2: patch_1 --]
[-- Type: text/plain, Size: 47911 bytes --]
gdb/
* Makefile.in (ALL_TARGET_OBJS): Add tilegx-tdep.o, tilegx-linux-tdep.o.
(ALLDEPFILES): tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c.
* configure.tgt: Add tilegx target.
* tilegx-tdep.h: New file.
* tilegx-tdep.c: New file.
* tilegx-linux-tdep.c: New file.
* regformats/reg-tilegx.dat: New file.
diff -r -u -N /home/packages/gdb-7.4x/gdb/configure.tgt ./gdb/configure.tgt
--- /home/packages/gdb-7.4x/gdb/configure.tgt 2012-03-05 06:41:51.000000000 -0500
+++ ./gdb/configure.tgt 2012-05-29 09:35:10.055133000 -0400
@@ -551,6 +551,13 @@
gdb_target_obs="tic6x-tdep.o"
;;
+tilegx-*-linux*)
+ # Target: TILE-Gx
+ gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
+ symfile-mem.o glibc-tdep.o linux-tdep.o"
+ ;;
+
+
xstormy16-*-*)
# Target: Sanyo Xstormy16a processor
gdb_target_obs="xstormy16-tdep.o"
diff -r -u -N /home/packages/gdb-7.4x/gdb/Makefile.in ./gdb/Makefile.in
--- /home/packages/gdb-7.4x/gdb/Makefile.in 2012-03-28 17:31:18.000000000 -0400
+++ ./gdb/Makefile.in 2012-05-29 09:35:09.951137000 -0400
@@ -565,6 +565,7 @@
sparc-sol2-tdep.o sparc-tdep.o \
spu-tdep.o spu-multiarch.o solib-spu.o \
tic6x-tdep.o tic6x-linux-tdep.o \
+ tilegx-tdep.o tilegx-linux-tdep.o \
v850-tdep.o \
vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
xstormy16-tdep.o \
@@ -1510,6 +1511,7 @@
sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
+ tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c \
v850-tdep.c \
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
windows-nat.c windows-tdep.c \
diff -r -u -N /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat ./gdb/regformats/reg-tilegx.dat
--- /home/packages/gdb-7.4x/gdb/regformats/reg-tilegx.dat 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/regformats/reg-tilegx.dat 2012-05-29 09:35:10.182128000 -0400
@@ -0,0 +1,67 @@
+name:tile
+expedite:sp,lr,pc
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:r32
+64:r33
+64:r34
+64:r35
+64:r36
+64:r37
+64:r38
+64:r39
+64:r40
+64:r41
+64:r42
+64:r43
+64:r44
+64:r45
+64:r46
+64:r47
+64:r48
+64:r49
+64:r50
+64:r51
+64:r52
+64:tp
+64:sp
+64:lr
+64:sn
+64:io0
+64:io1
+64:us0
+64:us1
+64:us2
+64:us3
+64:zero
+64:pc
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c ./gdb/tilegx-linux-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-linux-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-linux-tdep.c 2012-05-29 09:35:10.225123000 -0400
@@ -0,0 +1,148 @@
+/* Target-dependent code for GNU/Linux on Xtensa processors.
+
+ Copyright 2012 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 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 "osabi.h"
+#include "linux-tdep.h"
+#include "glibc-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "regcache.h"
+#include "regset.h"
+#include "tramp-frame.h"
+#include "trad-frame.h"
+
+#include "tilegx-tdep.h"
+
+/* Signal trampoline support. */
+
+static void
+tilegx_linux_sigframe_init (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ CORE_ADDR pc = get_frame_register_unsigned (this_frame, 64);
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, 54);
+ CORE_ADDR base = sp + 16;
+ int i;
+
+ for (i = 0; i < 56; i++)
+ trad_frame_set_reg_addr (this_cache, i, base + i * 8);
+
+ trad_frame_set_reg_value (this_cache, 64, pc);
+
+ /* Save a frame ID. */
+ trad_frame_set_id (this_cache, frame_id_build (base, func));
+}
+
+static const struct tramp_frame tilegx_linux_rt_sigframe =
+{
+ SIGTRAMP_FRAME,
+ 8,
+ {
+ { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
+ { 0x286b180051485000, -1 }, /* { swint1 } */
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ tilegx_linux_sigframe_init
+};
+
+/* Supply raw registers from REGCACHE to REGS. */
+
+static void
+tilegx_linux_supply_regset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *regs, size_t len)
+{
+ struct gdbarch *arch = get_regcache_arch (regcache);
+ const char *ptr = regs;
+ int i;
+
+ /* This logic must match that of struct pt_regs in "ptrace.h". */
+ for (i = 0; i < TILEGX_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size)
+ {
+ int gri = (i < TILEGX_NUM_EASY_REGS) ? i : TILEGX_PC_REGNUM;
+
+ if (regnum == gri || regnum == -1)
+ regcache_raw_supply (regcache, gri, ptr);
+ }
+}
+
+
+/* TILE-Gx Linux kernel register set. */
+static struct regset tilegx_linux_regset =
+{
+ NULL,
+ tilegx_linux_supply_regset
+};
+
+static const struct regset *
+tilegx_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ if (strcmp (sect_name, ".reg") == 0)
+ return &tilegx_linux_regset;
+
+ return NULL;
+}
+
+/* OS specific initialization of gdbarch. */
+
+static void
+tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ int arch_size = gdbarch_addr_bit (gdbarch);
+
+ linux_init_abi (info, gdbarch);
+
+ tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
+
+ set_gdbarch_regset_from_core_section (gdbarch,
+ tilegx_regset_from_core_section);
+
+ /* GNU/Linux uses SVR4-style shared libraries. */
+ if (arch_size == 32)
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+ else
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
+
+ /* Shared library handling. */
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_linux_tdep;
+
+void
+_initialize_tilegx_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_tilegx, bfd_mach_tilegx, GDB_OSABI_LINUX,
+ tilegx_linux_init_abi);
+}
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
--- /home/packages/gdb-7.4x/gdb/tilegx-tdep.c 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.c 2012-05-29 09:35:10.070125000 -0400
@@ -0,0 +1,1023 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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 "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "dis-asm.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "regset.h"
+#include "doublest.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "objfiles.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+
+#include "tilegx-tdep.h"
+
+#include "opcode/tilegx.h"
+
+struct tilegx_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ /* Function start. */
+ CORE_ADDR start_pc;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Register state values used by analyze_prologue. */
+enum reverse_state {
+ REVERSE_STATE_REGISTER,
+ REVERSE_STATE_VALUE,
+ REVERSE_STATE_UNKNOWN
+};
+
+/* Register state used by analyze_prologue(). */
+struct tilegx_reverse_regs
+{
+ LONGEST value;
+ enum reverse_state state;
+};
+
+static const struct tilegx_reverse_regs
+template_reverse_regs[TILEGX_NUM_PHYS_REGS] =
+ {
+ { TILEGX_R0_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R1_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R2_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R3_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R4_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R5_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R6_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R7_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R8_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R9_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R10_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R11_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R12_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R13_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R14_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R15_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R16_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R17_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R18_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R19_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R20_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R21_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R22_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R23_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R24_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R25_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R26_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R27_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R28_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R29_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R30_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R31_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R32_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R33_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R34_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R35_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R36_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R37_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R38_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R39_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R40_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R41_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R42_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R43_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R44_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R45_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R46_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R47_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R48_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R49_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R50_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R51_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R52_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_TP_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_SP_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_LR_REGNUM, REVERSE_STATE_REGISTER },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { TILEGX_ZERO_REGNUM, REVERSE_STATE_VALUE }
+ };
+
+/* Implement the "register_name" gdbarch method. */
+
+static const char *
+tilegx_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ static const char *const register_names[TILEGX_NUM_REGS] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr",
+ "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero",
+ "pc"
+ };
+
+ if (regnum < 0 || regnum >= TILEGX_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "tilegx_register_name: illegal register number %d",
+ regnum);
+
+ return register_names[regnum];
+}
+
+/* This is the implementation of gdbarch method register_type. */
+
+static struct type *
+tilegx_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == TILEGX_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+}
+
+/* This is the implementation of gdbarch method dwarf2_reg_to_regnum. */
+
+static int
+tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ return num;
+}
+
+
+/* Makes the decision if a given type is a scalar type. Scalar
+ types are returned in the registers r2-r11 as they fit. */
+
+static int
+tilegx_type_is_scalar (struct type *t)
+{
+ return (TYPE_CODE(t) != TYPE_CODE_STRUCT
+ && TYPE_CODE(t) != TYPE_CODE_UNION
+ && TYPE_CODE(t) != TYPE_CODE_ARRAY);
+}
+
+/* Returns non-zero if the given struct type will be returned using
+ a special convention, rather than the normal function return method.
+ Used in the context of the "return" command, and target function
+ calls from the debugger. */
+
+static int
+tilegx_use_struct_convention (struct type *type)
+{
+ /* Only scalars which fit in R0 - R9 can be returned in registers.
+ Otherwise, they are returned via a pointer passed in R0. */
+ return !tilegx_type_is_scalar (type)
+ && (TYPE_LENGTH (type) > (1 + TILEGX_R9_REGNUM - TILEGX_R0_REGNUM)
+ * tilegx_reg_size);
+}
+
+/* Find a function's return value in the appropriate registers (in
+ regbuf), and copy it into valbuf. */
+
+static void
+tilegx_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ int i, regnum = TILEGX_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_read (regcache, regnum++, valbuf + i);
+}
+
+/* Copy the function return value from VALBUF into the proper
+ location for a function return.
+ Called only in the context of the "return" command. */
+
+static void
+tilegx_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ if (TYPE_LENGTH (type) < tilegx_reg_size)
+ {
+ /* Add leading zeros to the (little-endian) value. */
+ gdb_byte buf[tilegx_reg_size] = { 0 };
+
+ memcpy (buf, valbuf, TYPE_LENGTH (type));
+ regcache_raw_write (regcache, TILEGX_R0_REGNUM, buf);
+ }
+ else
+ {
+ int len = TYPE_LENGTH (type);
+ int i, regnum = TILEGX_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_write (regcache, regnum++, (gdb_byte *) valbuf + i);
+ }
+}
+
+/* This is the implementation of gdbarch method return_value. */
+
+static enum return_value_convention
+tilegx_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (tilegx_use_struct_convention (type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ if (writebuf)
+ tilegx_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ tilegx_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* This is the implementation of gdbarch method frame_align. */
+
+static CORE_ADDR
+tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return addr & -8;
+}
+
+
+/* Implement the "push_dummy_call" gdbarch method. */
+
+static CORE_ADDR
+tilegx_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);
+ CORE_ADDR stack_dest = sp;
+ int argreg = TILEGX_R0_REGNUM;
+ int i, j;
+ int typelen, slacklen, alignlen;
+ static const gdb_byte two_zero_words[8] = { 0 };
+
+ /* If struct_return is 1, then the struct return address will
+ consume one argument-passing register. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
+
+ /* Arguments are passed in R0 - R9, and as soon as an argument
+ will not fit completely in the remaining registers, then it,
+ and all remaining arguments, are put on the stack. */
+ for (i = 0; i < nargs && argreg <= TILEGX_R9_REGNUM; i++)
+ {
+ const gdb_byte *val;
+ typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
+
+ if (typelen > (TILEGX_R9_REGNUM - argreg + 1) * tilegx_reg_size)
+ break;
+
+ /* Put argument into registers wordwise. */
+ val = value_contents (args[i]);
+ for (j = 0; j < typelen; j += tilegx_reg_size)
+ {
+ /* ISSUE: Why special handling for "typelen = 4x + 1"?
+ I don't ever see "typelen" values except 4 and 8. */
+ int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
+ ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
+
+ regcache_cooked_write_unsigned (regcache, argreg++, w);
+ }
+ }
+
+ /* Align SP. */
+ stack_dest = tilegx_frame_align (gdbarch, stack_dest);
+
+ /* Loop backwards through arguments to determine stack alignment. */
+ alignlen = 0;
+
+ for (j = nargs - 1; j >= i; j--)
+ {
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ alignlen += (typelen + 3) & (~3);
+ }
+
+ if (alignlen & 0x4)
+ stack_dest -= 4;
+
+ /* Loop backwards through remaining arguments and push them on
+ the stack, word aligned. */
+ for (j = nargs - 1; j >= i; j--)
+ {
+ gdb_byte *val;
+
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ slacklen = ((typelen + 3) & (~3)) - typelen;
+ val = alloca (typelen + slacklen);
+ memcpy (val, value_contents (args[j]), typelen);
+ memset (val + typelen, 0, slacklen);
+
+ /* Now write data to the stack. The stack grows downwards. */
+ stack_dest -= typelen + slacklen;
+ write_memory (stack_dest, val, typelen + slacklen);
+ }
+
+ /* Add 2 words for linkage space to the stack. */
+ stack_dest = stack_dest - 8;
+ write_memory (stack_dest, two_zero_words, 8);
+
+ /* Update stack pointer. */
+ regcache_cooked_write_unsigned (regcache, TILEGX_SP_REGNUM, stack_dest);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_unsigned (regcache, TILEGX_LR_REGNUM, bp_addr);
+
+ return stack_dest;
+}
+
+
+/* Decode the instructions within the given address range.
+ Decide when we must have reached the end of the function prologue.
+ If a frame_info pointer is provided, fill in its saved_regs etc.
+ Returns the address of the first instruction after the prologue.
+ NOTE: This is often called with start_addr being the start of some
+ function, and end_addr being the current PC. */
+
+static CORE_ADDR
+tilegx_analyze_prologue (struct gdbarch* gdbarch,
+ CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct tilegx_frame_cache *cache,
+ struct frame_info *next_frame)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR next_addr;
+ CORE_ADDR prolog_end = end_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+ gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
+ CORE_ADDR instbuf_start;
+ unsigned int instbuf_size;
+ int status;
+ bfd_uint64_t bundle;
+ struct tilegx_decoded_instruction
+ decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int num_insns;
+ struct tilegx_reverse_regs reverse_frame[TILEGX_NUM_PHYS_REGS];
+ struct tilegx_reverse_regs
+ new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int reverse_frame_valid, prolog_done, branch_seen;
+ LONGEST prev_sp_value;
+ int i, j;
+
+ if (start_addr >= end_addr
+ || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
+ return end_addr;
+
+ /* Initialize the reverse frame. This maps the CURRENT frame's
+ registers to the outer frame's registers (the frame on the
+ stack goes the other way). */
+ memcpy (&reverse_frame, &template_reverse_regs,
+ sizeof (reverse_frame));
+
+ prolog_done = 0;
+ branch_seen = 0;
+ prev_sp_value = 0;
+
+ /* To cut down on round-trip overhead, we fetch multiple bundles
+ at once. These variables describe the range of memory we have
+ prefetched. */
+ instbuf_start = 0;
+ instbuf_size = 0;
+
+ for (next_addr = start_addr; next_addr < end_addr;
+ next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
+ {
+ /* Retrieve the next instruction. */
+ if (next_addr - instbuf_start >= instbuf_size)
+ {
+ /* Figure out how many bytes to fetch. Don't span a page
+ boundary since that might cause an unnecessary memory
+ error. */
+ unsigned int size_on_same_page = 4096 - (next_addr & 4095);
+ instbuf_size = sizeof instbuf;
+
+ if (instbuf_size > size_on_same_page)
+ instbuf_size = size_on_same_page;
+ instbuf_start = next_addr;
+
+ status = safe_frame_unwind_memory (next_frame, instbuf_start,
+ instbuf, instbuf_size);
+ if (status == 0)
+ memory_error (status, next_addr);
+ }
+
+ reverse_frame_valid = 0;
+
+ bundle = extract_unsigned_integer (&instbuf[next_addr
+ - instbuf_start],
+ 8, byte_order);
+
+ num_insns = parse_insn_tilegx (bundle, next_addr, decoded);
+
+ for (i = 0; i < num_insns; i++)
+ {
+ struct tilegx_decoded_instruction *this_insn = &decoded[i];
+ int64_t *operands = (int64_t *) this_insn->operand_values;
+ const struct tilegx_opcode *opcode = this_insn->opcode;
+
+ switch (opcode->mnemonic)
+ {
+ case TILEGX_OPC_ST:
+ if (cache
+ && reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].state
+ == REVERSE_STATE_REGISTER)
+ {
+ LONGEST saved_address = reverse_frame[operands[0]].value;
+ unsigned saved_register
+ = (unsigned) reverse_frame[operands[1]].value;
+
+ /* realreg >= 0 and addr != -1 indicates that the
+ value of saved_register is in memory location
+ saved_address. The value of realreg is not
+ meaningful in this case but it must be >= 0.
+ See trad-frame.h. */
+ cache->saved_regs[saved_register].realreg = saved_register;
+ cache->saved_regs[saved_register].addr = saved_address;
+ }
+ break;
+ case TILEGX_OPC_ADDI:
+ case TILEGX_OPC_ADDLI:
+ if (cache
+ && operands[0] == TILEGX_SP_REGNUM
+ && operands[1] == TILEGX_SP_REGNUM
+ && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER)
+ {
+ /* Special case. We're fixing up the stack frame. */
+ uint64_t hopefully_sp
+ = (unsigned) reverse_frame[operands[1]].value;
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+ prev_sp_value = (cache->saved_regs[hopefully_sp].addr
+ - op2_as_short);
+
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value
+ = cache->saved_regs[hopefully_sp].addr;
+ trad_frame_set_value (cache->saved_regs,
+ hopefully_sp, prev_sp_value);
+ }
+ else
+ {
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
+ new_reverse_frame[i].value += op2_as_short;
+ else
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ADD:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ new_reverse_frame[i].value
+ += reverse_frame[operands[i]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVE:
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVEI:
+ case TILEGX_OPC_MOVELI:
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value = operands[1];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ORI:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have a value in A -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ = reverse_frame[operands[1]].value | operands[2];
+ }
+ else if (operands[2] == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_OR:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ }
+ else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_SUB:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ -= reverse_frame[operands[2]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+
+ case TILEGX_OPC_FNOP:
+ case TILEGX_OPC_INFO:
+ case TILEGX_OPC_INFOL:
+ /* Nothing to see here, move on.
+ Note that real NOP is treated as a 'real' instruction
+ because someone must have intended that it be there.
+ It therefore terminates the prolog.
+ */
+ break;
+
+ case TILEGX_OPC_J:
+ case TILEGX_OPC_JAL:
+
+ case TILEGX_OPC_BEQZ:
+ case TILEGX_OPC_BEQZT:
+ case TILEGX_OPC_BGEZ:
+ case TILEGX_OPC_BGEZT:
+ case TILEGX_OPC_BGTZ:
+ case TILEGX_OPC_BGTZT:
+ case TILEGX_OPC_BLBC:
+ case TILEGX_OPC_BLBCT:
+ case TILEGX_OPC_BLBS:
+ case TILEGX_OPC_BLBST:
+ case TILEGX_OPC_BLEZ:
+ case TILEGX_OPC_BLEZT:
+ case TILEGX_OPC_BLTZ:
+ case TILEGX_OPC_BLTZT:
+ case TILEGX_OPC_BNEZ:
+ case TILEGX_OPC_BNEZT:
+
+ case TILEGX_OPC_IRET:
+ case TILEGX_OPC_JALR:
+ case TILEGX_OPC_JALRP:
+ case TILEGX_OPC_JR:
+ case TILEGX_OPC_JRP:
+ case TILEGX_OPC_SWINT0:
+ case TILEGX_OPC_SWINT1:
+ case TILEGX_OPC_SWINT2:
+ case TILEGX_OPC_SWINT3:
+ /* We're really done -- this is a branch. */
+ branch_seen = 1;
+ prolog_done = 1;
+ break;
+ default:
+ /* We don't know or care what this instruction is.
+ All we know is that it isn't part of a prolog, and if
+ there's a destination register, we're trashing it. */
+ prolog_done = 1;
+ for (j = 0; j < opcode->num_operands; j++)
+ {
+ if (this_insn->operands[j]->is_dest_reg)
+ {
+ dest_regs[i] = operands[j];
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ reverse_frame_valid |= 1 << i;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now update the reverse frames. */
+ for (i = 0; i < num_insns; i++)
+ {
+ /* ISSUE: Does this properly handle "network" registers? */
+ if ((reverse_frame_valid & (1 << i))
+ && dest_regs[i] != TILEGX_ZERO_REGNUM)
+ reverse_frame[dest_regs[i]] = new_reverse_frame[i];
+ }
+
+ if (prev_sp_value != 0)
+ {
+ /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */
+ if (reverse_frame[TILEGX_R52_REGNUM].state == REVERSE_STATE_REGISTER
+ && reverse_frame[TILEGX_R52_REGNUM].value == TILEGX_SP_REGNUM)
+ {
+ reverse_frame[TILEGX_R52_REGNUM].state = REVERSE_STATE_VALUE;
+ reverse_frame[TILEGX_R52_REGNUM].value = prev_sp_value;
+ }
+
+ prev_sp_value = 0;
+ }
+
+ if (prolog_done && prolog_end == end_addr)
+ {
+ /* We found non-prolog code. As such, _this_ instruction
+ is the one after the prolog. We keep processing, because
+ there may be more prolog code in there, but this is what
+ we'll return. */
+ /* ISSUE: There may not have actually been a prologue, and
+ we may have simply skipped some random instructions. */
+ prolog_end = next_addr;
+ }
+ if (branch_seen)
+ {
+ /* We saw a branch. The prolog absolutely must be over. */
+ break;
+ }
+ }
+
+ if (prolog_end == end_addr && cache)
+ {
+ /* We may have terminated the prolog early, and we're certainly
+ at THIS point right now. It's possible that the values of
+ registers we need are currently actually in other registers
+ (and haven't been written to memory yet). Go find them. */
+ for (i = 0; i < TILEGX_NUM_PHYS_REGS; i++)
+ {
+ if (reverse_frame[i].state == REVERSE_STATE_REGISTER
+ && reverse_frame[i].value != i)
+ {
+ unsigned saved_register = (unsigned) reverse_frame[i].value;
+
+ cache->saved_regs[saved_register].realreg = i;
+ cache->saved_regs[saved_register].addr = (LONGEST) -1;
+ }
+ }
+ }
+
+ return prolog_end;
+}
+
+/* This is the implementation of gdbarch method skip_prologue. */
+
+static CORE_ADDR
+tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end && pc <= sal.end)
+ return sal.end;
+ }
+
+ /* Otherwise, try to skip prologue the hard way. */
+ return tilegx_analyze_prologue (gdbarch,
+ pc, pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES,
+ NULL, NULL);
+}
+
+/* This is the implementation of gdbarch method in_function_epilogue_p. */
+
+static int
+tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0, func_end = 0;
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ ULONGEST inst, inst2;
+ CORE_ADDR addr = func_end - TILEGX_BUNDLE_SIZE_IN_BYTES;
+
+ /* FIXME: Find the actual epilogue. */
+ /* HACK: Just assume the final bundle is the "ret" instruction". */
+ if (pc > addr)
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the implementation of gdbarch method breakpoint_from_pc. */
+
+static const unsigned char *
+tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
+{
+ /* 64-bit pattern for a { bpt ; nop } bundle. */
+ static const unsigned char breakpoint[] =
+ { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+/* Normal frames. */
+
+static struct tilegx_frame_cache *
+tilegx_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct tilegx_frame_cache *cache;
+ CORE_ADDR current_pc;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct tilegx_frame_cache);
+ *this_cache = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+ cache->base = 0;
+ cache->start_pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+
+ cache->base = get_frame_register_unsigned (this_frame, TILEGX_SP_REGNUM);
+ trad_frame_set_value (cache->saved_regs, TILEGX_SP_REGNUM, cache->base);
+
+ cache->saved_regs[TILEGX_PC_REGNUM] = cache->saved_regs[TILEGX_LR_REGNUM];
+ if (cache->start_pc)
+ tilegx_analyze_prologue (gdbarch, cache->start_pc, current_pc,
+ cache, this_frame);
+
+ return cache;
+}
+
+/* Retrieve the value of REGNUM in FRAME. */
+
+static struct value*
+tilegx_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int regnum)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs,
+ regnum);
+}
+
+/* Build frame id. */
+
+static void
+tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (info->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (info->base, info->start_pc);
+}
+
+static CORE_ADDR
+tilegx_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct tilegx_frame_cache *cache =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_unwind tilegx_frame_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ tilegx_frame_this_id,
+ tilegx_frame_prev_register,
+ NULL, /* const struct frame_data *unwind_data */
+ default_frame_sniffer, /* frame_sniffer_ftype *sniffer */
+ NULL /* frame_prev_pc_ftype *prev_pc */
+};
+
+static const struct frame_base tilegx_frame_base = {
+ &tilegx_frame_unwind,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address
+};
+
+static CORE_ADDR
+tilegx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, TILEGX_SP_REGNUM);
+}
+
+static CORE_ADDR
+tilegx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, TILEGX_PC_REGNUM);
+}
+
+static struct frame_id
+tilegx_unwind_dummy_id (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+
+ sp = get_frame_register_unsigned (this_frame, TILEGX_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+
+/* We cannot read/write the "special" registers. */
+
+static int
+tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno)
+{
+ if (regno >= 0 && regno < TILEGX_NUM_EASY_REGS)
+ return 0;
+ else if (regno == TILEGX_PC_REGNUM)
+ return 0;
+ else
+ return 1;
+}
+
+static struct gdbarch *
+tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ int arch_size = 64;
+
+ /* Handle arch_size == 32 or 64. Default to 64. */
+ if (info.abfd)
+ arch_size = bfd_get_arch_size (info.abfd);
+
+ if (arch_size != 32)
+ arch_size = 64;
+
+ /* Try to find a pre-existing architecture. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* We only have two flavors -- just make sure arch_size matches. */
+ if (gdbarch_ptr_bit (arches->gdbarch) == arch_size)
+ return (arches->gdbarch);
+ }
+
+ gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Basic register fields and methods, datatype sizes and stuff. */
+
+ /* There are 64 physical registers which can be referenced by
+ instructions (although only 56 of them can actually be
+ debugged) and 1 magic register (the PC). The other three
+ magic registers (ex1, syscall, orig_r0) which are known to
+ "ptrace" are ignored by "gdb". Note that we simply pretend
+ that there are 65 registers, and no "pseudo registers". */
+ set_gdbarch_num_regs (gdbarch, TILEGX_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+ set_gdbarch_sp_regnum (gdbarch, TILEGX_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, TILEGX_PC_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, tilegx_register_name);
+ set_gdbarch_register_type (gdbarch, tilegx_register_type);
+
+ set_gdbarch_char_signed (gdbarch, 0);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, arch_size);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_ptr_bit (gdbarch, arch_size);
+ set_gdbarch_addr_bit (gdbarch, arch_size);
+
+ set_gdbarch_cannot_fetch_register (gdbarch,
+ tilegx_cannot_reference_register);
+ set_gdbarch_cannot_store_register (gdbarch,
+ tilegx_cannot_reference_register);
+
+ /* Stack grows down. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Frame Info. */
+ set_gdbarch_unwind_sp (gdbarch, tilegx_unwind_sp);
+ set_gdbarch_unwind_pc (gdbarch, tilegx_unwind_pc);
+ set_gdbarch_dummy_id (gdbarch, tilegx_unwind_dummy_id);
+ set_gdbarch_frame_align (gdbarch, tilegx_frame_align);
+ frame_base_set_default (gdbarch, &tilegx_frame_base);
+
+ set_gdbarch_skip_prologue (gdbarch, tilegx_skip_prologue);
+
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ tilegx_in_function_epilogue_p);
+
+ /* Map debug registers into internal register numbers. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, tilegx_dwarf2_reg_to_regnum);
+
+ /* These values and methods are used when gdb calls a target function. */
+ set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call);
+ set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc);
+ set_gdbarch_return_value (gdbarch, tilegx_return_value);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_tilegx);
+
+ gdbarch_init_osabi (info, gdbarch);
+
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &tilegx_frame_unwind);
+
+ return gdbarch;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_tdep;
+
+void
+_initialize_tilegx_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
+}
diff -r -u -N /home/packages/gdb-7.4x/gdb/tilegx-tdep.h ./gdb/tilegx-tdep.h
--- /home/packages/gdb-7.4x/gdb/tilegx-tdep.h 1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.h 2012-05-29 09:35:10.206128000 -0400
@@ -0,0 +1,103 @@
+
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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/>. */
+
+
+/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
+ plus 8 special general purpose registers (network and ZERO),
+ plus 1 magic register (PC).
+
+ TP (aka R53) is the thread specific data pointer.
+ SP (aka R54) is the stack pointer.
+ LR (aka R55) is the link register.
+ */
+enum {
+ TILEGX_R0_REGNUM,
+ TILEGX_R1_REGNUM,
+ TILEGX_R2_REGNUM,
+ TILEGX_R3_REGNUM,
+ TILEGX_R4_REGNUM,
+ TILEGX_R5_REGNUM,
+ TILEGX_R6_REGNUM,
+ TILEGX_R7_REGNUM,
+ TILEGX_R8_REGNUM,
+ TILEGX_R9_REGNUM,
+ TILEGX_R10_REGNUM,
+ TILEGX_R11_REGNUM,
+ TILEGX_R12_REGNUM,
+ TILEGX_R13_REGNUM,
+ TILEGX_R14_REGNUM,
+ TILEGX_R15_REGNUM,
+ TILEGX_R16_REGNUM,
+ TILEGX_R17_REGNUM,
+ TILEGX_R18_REGNUM,
+ TILEGX_R19_REGNUM,
+ TILEGX_R20_REGNUM,
+ TILEGX_R21_REGNUM,
+ TILEGX_R22_REGNUM,
+ TILEGX_R23_REGNUM,
+ TILEGX_R24_REGNUM,
+ TILEGX_R25_REGNUM,
+ TILEGX_R26_REGNUM,
+ TILEGX_R27_REGNUM,
+ TILEGX_R28_REGNUM,
+ TILEGX_R29_REGNUM,
+ TILEGX_R30_REGNUM,
+ TILEGX_R31_REGNUM,
+ TILEGX_R32_REGNUM,
+ TILEGX_R33_REGNUM,
+ TILEGX_R34_REGNUM,
+ TILEGX_R35_REGNUM,
+ TILEGX_R36_REGNUM,
+ TILEGX_R37_REGNUM,
+ TILEGX_R38_REGNUM,
+ TILEGX_R39_REGNUM,
+ TILEGX_R40_REGNUM,
+ TILEGX_R41_REGNUM,
+ TILEGX_R42_REGNUM,
+ TILEGX_R43_REGNUM,
+ TILEGX_R44_REGNUM,
+ TILEGX_R45_REGNUM,
+ TILEGX_R46_REGNUM,
+ TILEGX_R47_REGNUM,
+ TILEGX_R48_REGNUM,
+ TILEGX_R49_REGNUM,
+ TILEGX_R50_REGNUM,
+ TILEGX_R51_REGNUM,
+ TILEGX_R52_REGNUM,
+ TILEGX_TP_REGNUM,
+ TILEGX_SP_REGNUM,
+ TILEGX_LR_REGNUM,
+
+ TILEGX_SN_REGNUM, TILEGX_NUM_EASY_REGS = TILEGX_SN_REGNUM, /* 56 */
+ TILEGX_IO0_REGNUM,
+ TILEGX_IO1_REGNUM,
+ TILEGX_US0_REGNUM,
+ TILEGX_US1_REGNUM,
+ TILEGX_US2_REGNUM,
+ TILEGX_US3_REGNUM,
+ TILEGX_ZERO_REGNUM,
+
+ TILEGX_PC_REGNUM, TILEGX_NUM_PHYS_REGS = TILEGX_PC_REGNUM, /* 64 */
+
+ TILEGX_NUM_REGS /* 65 */
+};
+
+enum { tilegx_reg_size = 8 };
+
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-29 15:24 ` [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb) Jeff Kenton
@ 2012-05-29 17:11 ` Jeff Kenton
0 siblings, 0 replies; 16+ messages in thread
From: Jeff Kenton @ 2012-05-29 17:11 UTC (permalink / raw)
To: Pedro Alves; +Cc: Joel Brobecker, gdb-patches
On 05/29/2012 11:23 AM, Jeff Kenton wrote:
>
> Thanks.
>
> --jeff kenton
>
Apologies for the double posting. They are equivalent.
--jeff kenton
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-29 15:24 ` Jeff Kenton
@ 2012-05-30 19:56 ` Pedro Alves
2012-05-30 20:09 ` Jeff Kenton
2012-05-31 8:53 ` [patch] Compilation regression on older gcc + 32-bit host [Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)] Jan Kratochvil
0 siblings, 2 replies; 16+ messages in thread
From: Pedro Alves @ 2012-05-30 19:56 UTC (permalink / raw)
To: Jeff Kenton; +Cc: Joel Brobecker, gdb-patches
Hi Jeff,
On 05/29/2012 04:24 PM, Jeff Kenton wrote:
> On 05/25/2012 11:17 AM, Pedro Alves wrote:
>> On 05/24/2012 08:26 PM, Jeff Kenton wrote:
>>
>>> On 05/23/2012 01:33 PM, Pedro Alves wrote:
>>>> Hi Jeff,
>>>>
>>>> On 05/21/2012 03:23 PM, Jeff Kenton wrote:
>>>>
>>>>
>>> - Comments applied.
>>> - SIGTRAMP frame handling improved.
>>> - Patch attached.
>>
>> For the future, it's easier for the reviewer if you reply to the issues
>> and questions raised. For example, in patch 2, I'm left wondering if the
>> ps_get_thread_area addition fixed any testsuite failures, indicating it is
>> correct. I'm also left wondering what does "improved" mean
>> (probably fixed something in the testsuite?).
>
> ps_get_thread_area didn't affect the testsuite results.
Okay, then it's either wrong, or unnecessary for some reason. Best
remove it (I've done that for you); we have a policy of not adding code
we don't understand.
>> Why is this 'if' necessary? Does bfd_get_arch_size ever return anything
>> not 32 or 64? In any case, you can just use gdbarch_addr_bit here,
>> as tilegx_gdbarch_init has already done the similar bfd_get_arch_size bit.
>
> Done.
There was another instance, I've removed it for you.
Please always send patches against the current mainline; the "tilegx_return_value"
function had a function signature that is no longer correct in mainline, and thus
caused an --enable-targets=all build to fail. I've fixed it.
I've also went through the patch and updated a series of formatting
issues (tabs/spaces, some alignments, etc.) and a few typos/pastos, as it was more
efficient that more back and forth. ;-) I've also done a couple other minor
things, like adding multiple inclusion guards to tilegx-tdep.h.
Here's the patch as checked in.
gdb/
* Makefile.in (ALL_TARGET_OBJS): Add tilegx-tdep.o and
tilegx-linux-tdep.o.
(ALLDEPFILES): Add tilegx-linux-nat.c, tilegx-tdep.c and
tilegx-linux-tdep.c.
* configure.tgt: Handle tilegx-*-linux*.
* tilegx-tdep.h: New file.
* tilegx-tdep.c: New file.
* tilegx-linux-tdep.c: New file.
* regformats/reg-tilegx.dat: New file.
---
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index b636045..bf6b0da 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -566,6 +566,7 @@ ALL_TARGET_OBS = \
sparc-sol2-tdep.o sparc-tdep.o \
spu-tdep.o spu-multiarch.o solib-spu.o \
tic6x-tdep.o tic6x-linux-tdep.o \
+ tilegx-tdep.o tilegx-linux-tdep.o \
v850-tdep.o \
vaxnbsd-tdep.o vaxobsd-tdep.o vax-tdep.o \
xstormy16-tdep.o \
@@ -1498,6 +1499,7 @@ ALLDEPFILES = \
sparc64nbsd-nat.c sparc64nbsd-tdep.c sparc64obsd-tdep.c \
sparcnbsd-nat.c sparcnbsd-tdep.c sparcobsd-tdep.c \
spu-linux-nat.c spu-tdep.c spu-multiarch.c solib-spu.c \
+ tilegx-linux-nat.c tilegx-tdep.c tilegx-linux-tdep.c \
v850-tdep.c \
vax-nat.c vax-tdep.c vaxbsd-nat.c vaxnbsd-tdep.c \
windows-nat.c windows-tdep.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 19c990e..7e2f9db 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -552,6 +552,12 @@ tic6x-*-*)
gdb_target_obs="tic6x-tdep.o"
;;
+tilegx-*-linux*)
+ # Target: TILE-Gx
+ gdb_target_obs="tilegx-tdep.o tilegx-linux-tdep.o solib-svr4.o \
+ symfile-mem.o glibc-tdep.o linux-tdep.o"
+ ;;
+
xstormy16-*-*)
# Target: Sanyo Xstormy16a processor
gdb_target_obs="xstormy16-tdep.o"
diff --git a/gdb/regformats/reg-tilegx.dat b/gdb/regformats/reg-tilegx.dat
new file mode 100644
index 0000000..fc971f9
--- /dev/null
+++ b/gdb/regformats/reg-tilegx.dat
@@ -0,0 +1,67 @@
+name:tile
+expedite:sp,lr,pc
+64:r0
+64:r1
+64:r2
+64:r3
+64:r4
+64:r5
+64:r6
+64:r7
+64:r8
+64:r9
+64:r10
+64:r11
+64:r12
+64:r13
+64:r14
+64:r15
+64:r16
+64:r17
+64:r18
+64:r19
+64:r20
+64:r21
+64:r22
+64:r23
+64:r24
+64:r25
+64:r26
+64:r27
+64:r28
+64:r29
+64:r30
+64:r31
+64:r32
+64:r33
+64:r34
+64:r35
+64:r36
+64:r37
+64:r38
+64:r39
+64:r40
+64:r41
+64:r42
+64:r43
+64:r44
+64:r45
+64:r46
+64:r47
+64:r48
+64:r49
+64:r50
+64:r51
+64:r52
+64:tp
+64:sp
+64:lr
+64:sn
+64:io0
+64:io1
+64:us0
+64:us1
+64:us2
+64:us3
+64:zero
+64:pc
diff --git a/gdb/tilegx-linux-tdep.c b/gdb/tilegx-linux-tdep.c
new file mode 100644
index 0000000..c7c6d9c
--- /dev/null
+++ b/gdb/tilegx-linux-tdep.c
@@ -0,0 +1,146 @@
+/* Target-dependent code for GNU/Linux on Tilera TILE-Gx processors.
+
+ Copyright 2012 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 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 "osabi.h"
+#include "linux-tdep.h"
+#include "glibc-tdep.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "regcache.h"
+#include "regset.h"
+#include "tramp-frame.h"
+#include "trad-frame.h"
+#include "tilegx-tdep.h"
+
+/* Signal trampoline support. */
+
+static void
+tilegx_linux_sigframe_init (const struct tramp_frame *self,
+ struct frame_info *this_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ CORE_ADDR pc = get_frame_register_unsigned (this_frame, 64);
+ CORE_ADDR sp = get_frame_register_unsigned (this_frame, 54);
+ CORE_ADDR base = sp + 16;
+ int i;
+
+ for (i = 0; i < 56; i++)
+ trad_frame_set_reg_addr (this_cache, i, base + i * 8);
+
+ trad_frame_set_reg_value (this_cache, 64, pc);
+
+ /* Save a frame ID. */
+ trad_frame_set_id (this_cache, frame_id_build (base, func));
+}
+
+static const struct tramp_frame tilegx_linux_rt_sigframe =
+{
+ SIGTRAMP_FRAME,
+ 8,
+ {
+ { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
+ { 0x286b180051485000, -1 }, /* { swint1 } */
+ { TRAMP_SENTINEL_INSN, -1 }
+ },
+ tilegx_linux_sigframe_init
+};
+
+/* Supply raw registers from REGCACHE to REGS. */
+
+static void
+tilegx_linux_supply_regset (const struct regset *regset,
+ struct regcache *regcache,
+ int regnum, const void *regs, size_t len)
+{
+ struct gdbarch *arch = get_regcache_arch (regcache);
+ const char *ptr = regs;
+ int i;
+
+ /* This logic must match that of struct pt_regs in "ptrace.h". */
+ for (i = 0; i < TILEGX_NUM_EASY_REGS + 1; i++, ptr += tilegx_reg_size)
+ {
+ int gri = (i < TILEGX_NUM_EASY_REGS) ? i : TILEGX_PC_REGNUM;
+
+ if (regnum == gri || regnum == -1)
+ regcache_raw_supply (regcache, gri, ptr);
+ }
+}
+
+/* TILE-Gx Linux kernel register set. */
+static struct regset tilegx_linux_regset =
+{
+ NULL,
+ tilegx_linux_supply_regset
+};
+
+static const struct regset *
+tilegx_regset_from_core_section (struct gdbarch *gdbarch,
+ const char *sect_name,
+ size_t sect_size)
+{
+ if (strcmp (sect_name, ".reg") == 0)
+ return &tilegx_linux_regset;
+
+ return NULL;
+}
+
+/* OS specific initialization of gdbarch. */
+
+static void
+tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ int arch_size = gdbarch_addr_bit (gdbarch);
+
+ linux_init_abi (info, gdbarch);
+
+ tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
+
+ set_gdbarch_regset_from_core_section (gdbarch,
+ tilegx_regset_from_core_section);
+
+ /* GNU/Linux uses SVR4-style shared libraries. */
+ if (arch_size == 32)
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_ilp32_fetch_link_map_offsets);
+ else
+ set_solib_svr4_fetch_link_map_offsets (gdbarch,
+ svr4_lp64_fetch_link_map_offsets);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
+
+ /* Shared library handling. */
+ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+ set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver);
+
+ set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_linux_tdep;
+
+void
+_initialize_tilegx_linux_tdep (void)
+{
+ gdbarch_register_osabi (bfd_arch_tilegx, bfd_mach_tilegx, GDB_OSABI_LINUX,
+ tilegx_linux_init_abi);
+}
diff --git a/gdb/tilegx-tdep.c b/gdb/tilegx-tdep.c
new file mode 100644
index 0000000..9ec3aaa
--- /dev/null
+++ b/gdb/tilegx-tdep.c
@@ -0,0 +1,1017 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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 "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "gdbcmd.h"
+#include "gdbcore.h"
+#include "value.h"
+#include "dis-asm.h"
+#include "inferior.h"
+#include "gdb_string.h"
+#include "gdb_assert.h"
+#include "arch-utils.h"
+#include "floatformat.h"
+#include "regcache.h"
+#include "regset.h"
+#include "doublest.h"
+#include "osabi.h"
+#include "linux-tdep.h"
+#include "objfiles.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+#include "tilegx-tdep.h"
+#include "opcode/tilegx.h"
+
+struct tilegx_frame_cache
+{
+ /* Base address. */
+ CORE_ADDR base;
+ /* Function start. */
+ CORE_ADDR start_pc;
+
+ /* Table of saved registers. */
+ struct trad_frame_saved_reg *saved_regs;
+};
+
+/* Register state values used by analyze_prologue. */
+enum reverse_state
+ {
+ REVERSE_STATE_REGISTER,
+ REVERSE_STATE_VALUE,
+ REVERSE_STATE_UNKNOWN
+ };
+
+/* Register state used by analyze_prologue(). */
+struct tilegx_reverse_regs
+{
+ LONGEST value;
+ enum reverse_state state;
+};
+
+static const struct tilegx_reverse_regs
+template_reverse_regs[TILEGX_NUM_PHYS_REGS] =
+ {
+ { TILEGX_R0_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R1_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R2_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R3_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R4_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R5_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R6_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R7_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R8_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R9_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R10_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R11_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R12_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R13_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R14_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R15_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R16_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R17_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R18_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R19_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R20_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R21_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R22_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R23_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R24_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R25_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R26_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R27_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R28_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R29_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R30_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R31_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R32_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R33_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R34_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R35_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R36_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R37_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R38_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R39_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R40_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R41_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R42_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R43_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R44_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R45_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R46_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R47_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R48_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R49_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R50_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R51_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_R52_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_TP_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_SP_REGNUM, REVERSE_STATE_REGISTER },
+ { TILEGX_LR_REGNUM, REVERSE_STATE_REGISTER },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { 0, REVERSE_STATE_UNKNOWN },
+ { TILEGX_ZERO_REGNUM, REVERSE_STATE_VALUE }
+ };
+
+/* Implement the "register_name" gdbarch method. */
+
+static const char *
+tilegx_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ static const char *const register_names[TILEGX_NUM_REGS] =
+ {
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr",
+ "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero",
+ "pc"
+ };
+
+ if (regnum < 0 || regnum >= TILEGX_NUM_REGS)
+ internal_error (__FILE__, __LINE__,
+ "tilegx_register_name: invalid register number %d",
+ regnum);
+
+ return register_names[regnum];
+}
+
+/* This is the implementation of gdbarch method register_type. */
+
+static struct type *
+tilegx_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ if (regnum == TILEGX_PC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ else
+ return builtin_type (gdbarch)->builtin_uint64;
+}
+
+/* This is the implementation of gdbarch method dwarf2_reg_to_regnum. */
+
+static int
+tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ return num;
+}
+
+/* Makes the decision of whether a given type is a scalar type.
+ Scalar types are returned in the registers r2-r11 as they fit. */
+
+static int
+tilegx_type_is_scalar (struct type *t)
+{
+ return (TYPE_CODE(t) != TYPE_CODE_STRUCT
+ && TYPE_CODE(t) != TYPE_CODE_UNION
+ && TYPE_CODE(t) != TYPE_CODE_ARRAY);
+}
+
+/* Returns non-zero if the given struct type will be returned using
+ a special convention, rather than the normal function return method.
+ Used in the context of the "return" command, and target function
+ calls from the debugger. */
+
+static int
+tilegx_use_struct_convention (struct type *type)
+{
+ /* Only scalars which fit in R0 - R9 can be returned in registers.
+ Otherwise, they are returned via a pointer passed in R0. */
+ return (!tilegx_type_is_scalar (type)
+ && (TYPE_LENGTH (type) > (1 + TILEGX_R9_REGNUM - TILEGX_R0_REGNUM)
+ * tilegx_reg_size));
+}
+
+/* Find a function's return value in the appropriate registers (in
+ REGCACHE), and copy it into VALBUF. */
+
+static void
+tilegx_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
+{
+ int len = TYPE_LENGTH (type);
+ int i, regnum = TILEGX_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_read (regcache, regnum++, valbuf + i);
+}
+
+/* Copy the function return value from VALBUF into the proper
+ location for a function return.
+ Called only in the context of the "return" command. */
+
+static void
+tilegx_store_return_value (struct type *type, struct regcache *regcache,
+ const void *valbuf)
+{
+ if (TYPE_LENGTH (type) < tilegx_reg_size)
+ {
+ /* Add leading zeros to the (little-endian) value. */
+ gdb_byte buf[tilegx_reg_size] = { 0 };
+
+ memcpy (buf, valbuf, TYPE_LENGTH (type));
+ regcache_raw_write (regcache, TILEGX_R0_REGNUM, buf);
+ }
+ else
+ {
+ int len = TYPE_LENGTH (type);
+ int i, regnum = TILEGX_R0_REGNUM;
+
+ for (i = 0; i < len; i += tilegx_reg_size)
+ regcache_raw_write (regcache, regnum++, (gdb_byte *) valbuf + i);
+ }
+}
+
+/* This is the implementation of gdbarch method return_value. */
+
+static enum return_value_convention
+tilegx_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+ if (tilegx_use_struct_convention (type))
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ if (writebuf)
+ tilegx_store_return_value (type, regcache, writebuf);
+ else if (readbuf)
+ tilegx_extract_return_value (type, regcache, readbuf);
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
+
+/* This is the implementation of gdbarch method frame_align. */
+
+static CORE_ADDR
+tilegx_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return addr & -8;
+}
+
+
+/* Implement the "push_dummy_call" gdbarch method. */
+
+static CORE_ADDR
+tilegx_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);
+ CORE_ADDR stack_dest = sp;
+ int argreg = TILEGX_R0_REGNUM;
+ int i, j;
+ int typelen, slacklen, alignlen;
+ static const gdb_byte two_zero_words[8] = { 0 };
+
+ /* If struct_return is 1, then the struct return address will
+ consume one argument-passing register. */
+ if (struct_return)
+ regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
+
+ /* Arguments are passed in R0 - R9, and as soon as an argument
+ will not fit completely in the remaining registers, then it,
+ and all remaining arguments, are put on the stack. */
+ for (i = 0; i < nargs && argreg <= TILEGX_R9_REGNUM; i++)
+ {
+ const gdb_byte *val;
+ typelen = TYPE_LENGTH (value_enclosing_type (args[i]));
+
+ if (typelen > (TILEGX_R9_REGNUM - argreg + 1) * tilegx_reg_size)
+ break;
+
+ /* Put argument into registers wordwise. */
+ val = value_contents (args[i]);
+ for (j = 0; j < typelen; j += tilegx_reg_size)
+ {
+ /* ISSUE: Why special handling for "typelen = 4x + 1"?
+ I don't ever see "typelen" values except 4 and 8. */
+ int n = (typelen - j == 1) ? 1 : tilegx_reg_size;
+ ULONGEST w = extract_unsigned_integer (val + j, n, byte_order);
+
+ regcache_cooked_write_unsigned (regcache, argreg++, w);
+ }
+ }
+
+ /* Align SP. */
+ stack_dest = tilegx_frame_align (gdbarch, stack_dest);
+
+ /* Loop backwards through arguments to determine stack alignment. */
+ alignlen = 0;
+
+ for (j = nargs - 1; j >= i; j--)
+ {
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ alignlen += (typelen + 3) & (~3);
+ }
+
+ if (alignlen & 0x4)
+ stack_dest -= 4;
+
+ /* Loop backwards through remaining arguments and push them on
+ the stack, word aligned. */
+ for (j = nargs - 1; j >= i; j--)
+ {
+ gdb_byte *val;
+
+ typelen = TYPE_LENGTH (value_enclosing_type (args[j]));
+ slacklen = ((typelen + 3) & (~3)) - typelen;
+ val = alloca (typelen + slacklen);
+ memcpy (val, value_contents (args[j]), typelen);
+ memset (val + typelen, 0, slacklen);
+
+ /* Now write data to the stack. The stack grows downwards. */
+ stack_dest -= typelen + slacklen;
+ write_memory (stack_dest, val, typelen + slacklen);
+ }
+
+ /* Add 2 words for linkage space to the stack. */
+ stack_dest = stack_dest - 8;
+ write_memory (stack_dest, two_zero_words, 8);
+
+ /* Update stack pointer. */
+ regcache_cooked_write_unsigned (regcache, TILEGX_SP_REGNUM, stack_dest);
+
+ /* Set the return address register to point to the entry point of
+ the program, where a breakpoint lies in wait. */
+ regcache_cooked_write_unsigned (regcache, TILEGX_LR_REGNUM, bp_addr);
+
+ return stack_dest;
+}
+
+
+/* Decode the instructions within the given address range.
+ Decide when we must have reached the end of the function prologue.
+ If a frame_info pointer is provided, fill in its saved_regs etc.
+ Returns the address of the first instruction after the prologue.
+ NOTE: This is often called with start_addr being the start of some
+ function, and end_addr being the current PC. */
+
+static CORE_ADDR
+tilegx_analyze_prologue (struct gdbarch* gdbarch,
+ CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct tilegx_frame_cache *cache,
+ struct frame_info *next_frame)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ CORE_ADDR next_addr;
+ CORE_ADDR prolog_end = end_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+ gdb_byte instbuf[32 * TILEGX_BUNDLE_SIZE_IN_BYTES];
+ CORE_ADDR instbuf_start;
+ unsigned int instbuf_size;
+ int status;
+ bfd_uint64_t bundle;
+ struct tilegx_decoded_instruction
+ decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int num_insns;
+ struct tilegx_reverse_regs reverse_frame[TILEGX_NUM_PHYS_REGS];
+ struct tilegx_reverse_regs
+ new_reverse_frame[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int dest_regs[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
+ int reverse_frame_valid, prolog_done, branch_seen;
+ LONGEST prev_sp_value;
+ int i, j;
+
+ if (start_addr >= end_addr
+ || (start_addr % TILEGX_BUNDLE_ALIGNMENT_IN_BYTES) != 0)
+ return end_addr;
+
+ /* Initialize the reverse frame. This maps the CURRENT frame's
+ registers to the outer frame's registers (the frame on the
+ stack goes the other way). */
+ memcpy (&reverse_frame, &template_reverse_regs, sizeof (reverse_frame));
+
+ prolog_done = 0;
+ branch_seen = 0;
+ prev_sp_value = 0;
+
+ /* To cut down on round-trip overhead, we fetch multiple bundles
+ at once. These variables describe the range of memory we have
+ prefetched. */
+ instbuf_start = 0;
+ instbuf_size = 0;
+
+ for (next_addr = start_addr;
+ next_addr < end_addr;
+ next_addr += TILEGX_BUNDLE_SIZE_IN_BYTES)
+ {
+ /* Retrieve the next instruction. */
+ if (next_addr - instbuf_start >= instbuf_size)
+ {
+ /* Figure out how many bytes to fetch. Don't span a page
+ boundary since that might cause an unnecessary memory
+ error. */
+ unsigned int size_on_same_page = 4096 - (next_addr & 4095);
+
+ instbuf_size = sizeof instbuf;
+
+ if (instbuf_size > size_on_same_page)
+ instbuf_size = size_on_same_page;
+ instbuf_start = next_addr;
+
+ status = safe_frame_unwind_memory (next_frame, instbuf_start,
+ instbuf, instbuf_size);
+ if (status == 0)
+ memory_error (status, next_addr);
+ }
+
+ reverse_frame_valid = 0;
+
+ bundle = extract_unsigned_integer (&instbuf[next_addr - instbuf_start],
+ 8, byte_order);
+
+ num_insns = parse_insn_tilegx (bundle, next_addr, decoded);
+
+ for (i = 0; i < num_insns; i++)
+ {
+ struct tilegx_decoded_instruction *this_insn = &decoded[i];
+ int64_t *operands = (int64_t *) this_insn->operand_values;
+ const struct tilegx_opcode *opcode = this_insn->opcode;
+
+ switch (opcode->mnemonic)
+ {
+ case TILEGX_OPC_ST:
+ if (cache
+ && reverse_frame[operands[0]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].state
+ == REVERSE_STATE_REGISTER)
+ {
+ LONGEST saved_address = reverse_frame[operands[0]].value;
+ unsigned saved_register
+ = (unsigned) reverse_frame[operands[1]].value;
+
+ /* realreg >= 0 and addr != -1 indicates that the
+ value of saved_register is in memory location
+ saved_address. The value of realreg is not
+ meaningful in this case but it must be >= 0.
+ See trad-frame.h. */
+ cache->saved_regs[saved_register].realreg = saved_register;
+ cache->saved_regs[saved_register].addr = saved_address;
+ }
+ break;
+ case TILEGX_OPC_ADDI:
+ case TILEGX_OPC_ADDLI:
+ if (cache
+ && operands[0] == TILEGX_SP_REGNUM
+ && operands[1] == TILEGX_SP_REGNUM
+ && reverse_frame[operands[1]].state == REVERSE_STATE_REGISTER)
+ {
+ /* Special case. We're fixing up the stack frame. */
+ uint64_t hopefully_sp
+ = (unsigned) reverse_frame[operands[1]].value;
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+ prev_sp_value = (cache->saved_regs[hopefully_sp].addr
+ - op2_as_short);
+
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value
+ = cache->saved_regs[hopefully_sp].addr;
+ trad_frame_set_value (cache->saved_regs,
+ hopefully_sp, prev_sp_value);
+ }
+ else
+ {
+ short op2_as_short = (short) operands[2];
+ signed char op2_as_char = (signed char) operands[2];
+
+ /* Fix up the sign-extension. */
+ if (opcode->mnemonic == TILEGX_OPC_ADDI)
+ op2_as_short = op2_as_char;
+
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ if (new_reverse_frame[i].state == REVERSE_STATE_VALUE)
+ new_reverse_frame[i].value += op2_as_short;
+ else
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ADD:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ new_reverse_frame[i].value
+ += reverse_frame[operands[i]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVE:
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_MOVEI:
+ case TILEGX_OPC_MOVELI:
+ new_reverse_frame[i].state = REVERSE_STATE_VALUE;
+ new_reverse_frame[i].value = operands[1];
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_ORI:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have a value in A -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ = reverse_frame[operands[1]].value | operands[2];
+ }
+ else if (operands[2] == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_OR:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[1]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[2]];
+ }
+ else if (reverse_frame[operands[2]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].value == 0)
+ {
+ /* This is a move. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+ case TILEGX_OPC_SUB:
+ if (reverse_frame[operands[1]].state == REVERSE_STATE_VALUE
+ && reverse_frame[operands[2]].state == REVERSE_STATE_VALUE)
+ {
+ /* We have values -- we can do this. */
+ new_reverse_frame[i] = reverse_frame[operands[1]];
+ new_reverse_frame[i].value
+ -= reverse_frame[operands[2]].value;
+ }
+ else
+ {
+ /* We don't know anything about the values. Punt. */
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ }
+ reverse_frame_valid |= 1 << i;
+ dest_regs[i] = operands[0];
+ break;
+
+ case TILEGX_OPC_FNOP:
+ case TILEGX_OPC_INFO:
+ case TILEGX_OPC_INFOL:
+ /* Nothing to see here, move on.
+ Note that real NOP is treated as a 'real' instruction
+ because someone must have intended that it be there.
+ It therefore terminates the prolog. */
+ break;
+
+ case TILEGX_OPC_J:
+ case TILEGX_OPC_JAL:
+
+ case TILEGX_OPC_BEQZ:
+ case TILEGX_OPC_BEQZT:
+ case TILEGX_OPC_BGEZ:
+ case TILEGX_OPC_BGEZT:
+ case TILEGX_OPC_BGTZ:
+ case TILEGX_OPC_BGTZT:
+ case TILEGX_OPC_BLBC:
+ case TILEGX_OPC_BLBCT:
+ case TILEGX_OPC_BLBS:
+ case TILEGX_OPC_BLBST:
+ case TILEGX_OPC_BLEZ:
+ case TILEGX_OPC_BLEZT:
+ case TILEGX_OPC_BLTZ:
+ case TILEGX_OPC_BLTZT:
+ case TILEGX_OPC_BNEZ:
+ case TILEGX_OPC_BNEZT:
+
+ case TILEGX_OPC_IRET:
+ case TILEGX_OPC_JALR:
+ case TILEGX_OPC_JALRP:
+ case TILEGX_OPC_JR:
+ case TILEGX_OPC_JRP:
+ case TILEGX_OPC_SWINT0:
+ case TILEGX_OPC_SWINT1:
+ case TILEGX_OPC_SWINT2:
+ case TILEGX_OPC_SWINT3:
+ /* We're really done -- this is a branch. */
+ branch_seen = 1;
+ prolog_done = 1;
+ break;
+ default:
+ /* We don't know or care what this instruction is.
+ All we know is that it isn't part of a prolog, and if
+ there's a destination register, we're trashing it. */
+ prolog_done = 1;
+ for (j = 0; j < opcode->num_operands; j++)
+ {
+ if (this_insn->operands[j]->is_dest_reg)
+ {
+ dest_regs[i] = operands[j];
+ new_reverse_frame[i].state = REVERSE_STATE_UNKNOWN;
+ reverse_frame_valid |= 1 << i;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Now update the reverse frames. */
+ for (i = 0; i < num_insns; i++)
+ {
+ /* ISSUE: Does this properly handle "network" registers? */
+ if ((reverse_frame_valid & (1 << i))
+ && dest_regs[i] != TILEGX_ZERO_REGNUM)
+ reverse_frame[dest_regs[i]] = new_reverse_frame[i];
+ }
+
+ if (prev_sp_value != 0)
+ {
+ /* GCC uses R52 as a frame pointer. Have we seen "move r52, sp"? */
+ if (reverse_frame[TILEGX_R52_REGNUM].state == REVERSE_STATE_REGISTER
+ && reverse_frame[TILEGX_R52_REGNUM].value == TILEGX_SP_REGNUM)
+ {
+ reverse_frame[TILEGX_R52_REGNUM].state = REVERSE_STATE_VALUE;
+ reverse_frame[TILEGX_R52_REGNUM].value = prev_sp_value;
+ }
+
+ prev_sp_value = 0;
+ }
+
+ if (prolog_done && prolog_end == end_addr)
+ {
+ /* We found non-prolog code. As such, _this_ instruction
+ is the one after the prolog. We keep processing, because
+ there may be more prolog code in there, but this is what
+ we'll return. */
+ /* ISSUE: There may not have actually been a prologue, and
+ we may have simply skipped some random instructions. */
+ prolog_end = next_addr;
+ }
+ if (branch_seen)
+ {
+ /* We saw a branch. The prolog absolutely must be over. */
+ break;
+ }
+ }
+
+ if (prolog_end == end_addr && cache)
+ {
+ /* We may have terminated the prolog early, and we're certainly
+ at THIS point right now. It's possible that the values of
+ registers we need are currently actually in other registers
+ (and haven't been written to memory yet). Go find them. */
+ for (i = 0; i < TILEGX_NUM_PHYS_REGS; i++)
+ {
+ if (reverse_frame[i].state == REVERSE_STATE_REGISTER
+ && reverse_frame[i].value != i)
+ {
+ unsigned saved_register = (unsigned) reverse_frame[i].value;
+
+ cache->saved_regs[saved_register].realreg = i;
+ cache->saved_regs[saved_register].addr = (LONGEST) -1;
+ }
+ }
+ }
+
+ return prolog_end;
+}
+
+/* This is the implementation of gdbarch method skip_prologue. */
+
+static CORE_ADDR
+tilegx_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ struct symtab_and_line sal;
+ CORE_ADDR func_start, func_end;
+
+ /* This is the preferred method, find the end of the prologue by
+ using the debugging information. */
+ if (find_pc_partial_function (pc, NULL, &func_start, &func_end))
+ {
+ sal = find_pc_line (func_start, 0);
+
+ if (sal.end < func_end && pc <= sal.end)
+ return sal.end;
+ }
+
+ /* Otherwise, try to skip prologue the hard way. */
+ return tilegx_analyze_prologue (gdbarch,
+ pc, pc + 8 * TILEGX_BUNDLE_SIZE_IN_BYTES,
+ NULL, NULL);
+}
+
+/* This is the implementation of gdbarch method in_function_epilogue_p. */
+
+static int
+tilegx_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ CORE_ADDR func_addr = 0, func_end = 0;
+
+ if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+ {
+ ULONGEST inst, inst2;
+ CORE_ADDR addr = func_end - TILEGX_BUNDLE_SIZE_IN_BYTES;
+
+ /* FIXME: Find the actual epilogue. */
+ /* HACK: Just assume the final bundle is the "ret" instruction". */
+ if (pc > addr)
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the implementation of gdbarch method breakpoint_from_pc. */
+
+static const unsigned char *
+tilegx_breakpoint_from_pc (struct gdbarch *gdbarch,
+ CORE_ADDR *pcptr, int *lenptr)
+{
+ /* 64-bit pattern for a { bpt ; nop } bundle. */
+ static const unsigned char breakpoint[] =
+ { 0x00, 0x50, 0x48, 0x51, 0xae, 0x44, 0x6a, 0x28 };
+
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+/* Normal frames. */
+
+static struct tilegx_frame_cache *
+tilegx_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
+ struct tilegx_frame_cache *cache;
+ CORE_ADDR current_pc;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = FRAME_OBSTACK_ZALLOC (struct tilegx_frame_cache);
+ *this_cache = cache;
+ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame);
+ cache->base = 0;
+ cache->start_pc = get_frame_func (this_frame);
+ current_pc = get_frame_pc (this_frame);
+
+ cache->base = get_frame_register_unsigned (this_frame, TILEGX_SP_REGNUM);
+ trad_frame_set_value (cache->saved_regs, TILEGX_SP_REGNUM, cache->base);
+
+ cache->saved_regs[TILEGX_PC_REGNUM] = cache->saved_regs[TILEGX_LR_REGNUM];
+ if (cache->start_pc)
+ tilegx_analyze_prologue (gdbarch, cache->start_pc, current_pc,
+ cache, this_frame);
+
+ return cache;
+}
+
+/* Retrieve the value of REGNUM in FRAME. */
+
+static struct value*
+tilegx_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache,
+ int regnum)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return trad_frame_get_prev_register (this_frame, info->saved_regs,
+ regnum);
+}
+
+/* Build frame id. */
+
+static void
+tilegx_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct tilegx_frame_cache *info =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ /* This marks the outermost frame. */
+ if (info->base == 0)
+ return;
+
+ (*this_id) = frame_id_build (info->base, info->start_pc);
+}
+
+static CORE_ADDR
+tilegx_frame_base_address (struct frame_info *this_frame, void **this_cache)
+{
+ struct tilegx_frame_cache *cache =
+ tilegx_frame_cache (this_frame, this_cache);
+
+ return cache->base;
+}
+
+static const struct frame_unwind tilegx_frame_unwind = {
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ tilegx_frame_this_id,
+ tilegx_frame_prev_register,
+ NULL, /* const struct frame_data *unwind_data */
+ default_frame_sniffer, /* frame_sniffer_ftype *sniffer */
+ NULL /* frame_prev_pc_ftype *prev_pc */
+};
+
+static const struct frame_base tilegx_frame_base = {
+ &tilegx_frame_unwind,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address,
+ tilegx_frame_base_address
+};
+
+static CORE_ADDR
+tilegx_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, TILEGX_SP_REGNUM);
+}
+
+static CORE_ADDR
+tilegx_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
+{
+ return frame_unwind_register_unsigned (next_frame, TILEGX_PC_REGNUM);
+}
+
+static struct frame_id
+tilegx_unwind_dummy_id (struct gdbarch *gdbarch,
+ struct frame_info *this_frame)
+{
+ CORE_ADDR sp;
+
+ sp = get_frame_register_unsigned (this_frame, TILEGX_SP_REGNUM);
+ return frame_id_build (sp, get_frame_pc (this_frame));
+}
+
+
+/* We cannot read/write the "special" registers. */
+
+static int
+tilegx_cannot_reference_register (struct gdbarch *gdbarch, int regno)
+{
+ if (regno >= 0 && regno < TILEGX_NUM_EASY_REGS)
+ return 0;
+ else if (regno == TILEGX_PC_REGNUM)
+ return 0;
+ else
+ return 1;
+}
+
+static struct gdbarch *
+tilegx_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
+{
+ struct gdbarch *gdbarch;
+ int arch_size = 64;
+
+ /* Handle arch_size == 32 or 64. Default to 64. */
+ if (info.abfd)
+ arch_size = bfd_get_arch_size (info.abfd);
+
+ /* Try to find a pre-existing architecture. */
+ for (arches = gdbarch_list_lookup_by_info (arches, &info);
+ arches != NULL;
+ arches = gdbarch_list_lookup_by_info (arches->next, &info))
+ {
+ /* We only have two flavors -- just make sure arch_size matches. */
+ if (gdbarch_ptr_bit (arches->gdbarch) == arch_size)
+ return (arches->gdbarch);
+ }
+
+ gdbarch = gdbarch_alloc (&info, NULL);
+
+ /* Basic register fields and methods, datatype sizes and stuff. */
+
+ /* There are 64 physical registers which can be referenced by
+ instructions (although only 56 of them can actually be
+ debugged) and 1 magic register (the PC). The other three
+ magic registers (ex1, syscall, orig_r0) which are known to
+ "ptrace" are ignored by "gdb". Note that we simply pretend
+ that there are 65 registers, and no "pseudo registers". */
+ set_gdbarch_num_regs (gdbarch, TILEGX_NUM_REGS);
+ set_gdbarch_num_pseudo_regs (gdbarch, 0);
+
+ set_gdbarch_sp_regnum (gdbarch, TILEGX_SP_REGNUM);
+ set_gdbarch_pc_regnum (gdbarch, TILEGX_PC_REGNUM);
+
+ set_gdbarch_register_name (gdbarch, tilegx_register_name);
+ set_gdbarch_register_type (gdbarch, tilegx_register_type);
+
+ set_gdbarch_char_signed (gdbarch, 0);
+ set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT);
+ set_gdbarch_int_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_long_bit (gdbarch, arch_size);
+ set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT);
+ set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
+ set_gdbarch_ptr_bit (gdbarch, arch_size);
+ set_gdbarch_addr_bit (gdbarch, arch_size);
+
+ set_gdbarch_cannot_fetch_register (gdbarch,
+ tilegx_cannot_reference_register);
+ set_gdbarch_cannot_store_register (gdbarch,
+ tilegx_cannot_reference_register);
+
+ /* Stack grows down. */
+ set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
+
+ /* Frame Info. */
+ set_gdbarch_unwind_sp (gdbarch, tilegx_unwind_sp);
+ set_gdbarch_unwind_pc (gdbarch, tilegx_unwind_pc);
+ set_gdbarch_dummy_id (gdbarch, tilegx_unwind_dummy_id);
+ set_gdbarch_frame_align (gdbarch, tilegx_frame_align);
+ frame_base_set_default (gdbarch, &tilegx_frame_base);
+
+ set_gdbarch_skip_prologue (gdbarch, tilegx_skip_prologue);
+
+ set_gdbarch_in_function_epilogue_p (gdbarch,
+ tilegx_in_function_epilogue_p);
+
+ /* Map debug registers into internal register numbers. */
+ set_gdbarch_dwarf2_reg_to_regnum (gdbarch, tilegx_dwarf2_reg_to_regnum);
+
+ /* These values and methods are used when gdb calls a target function. */
+ set_gdbarch_push_dummy_call (gdbarch, tilegx_push_dummy_call);
+ set_gdbarch_breakpoint_from_pc (gdbarch, tilegx_breakpoint_from_pc);
+ set_gdbarch_return_value (gdbarch, tilegx_return_value);
+
+ set_gdbarch_print_insn (gdbarch, print_insn_tilegx);
+
+ gdbarch_init_osabi (info, gdbarch);
+
+ dwarf2_append_unwinders (gdbarch);
+ frame_unwind_append_unwinder (gdbarch, &tilegx_frame_unwind);
+
+ return gdbarch;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_tilegx_tdep;
+
+void
+_initialize_tilegx_tdep (void)
+{
+ register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
+}
diff --git a/gdb/tilegx-tdep.h b/gdb/tilegx-tdep.h
new file mode 100644
index 0000000..3ac18a5
--- /dev/null
+++ b/gdb/tilegx-tdep.h
@@ -0,0 +1,109 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 2012 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 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/>. */
+
+#ifndef TILEGX_TDEP_H
+#define TILEGX_TDEP_H
+
+/* TILE-Gx has 56 general purpose registers (R0 - R52, TP, SP, LR),
+ plus 8 special general purpose registers (network and ZERO),
+ plus 1 magic register (PC).
+
+ TP (aka R53) is the thread specific data pointer.
+ SP (aka R54) is the stack pointer.
+ LR (aka R55) is the link register. */
+
+enum tilegx_regnum
+ {
+ TILEGX_R0_REGNUM,
+ TILEGX_R1_REGNUM,
+ TILEGX_R2_REGNUM,
+ TILEGX_R3_REGNUM,
+ TILEGX_R4_REGNUM,
+ TILEGX_R5_REGNUM,
+ TILEGX_R6_REGNUM,
+ TILEGX_R7_REGNUM,
+ TILEGX_R8_REGNUM,
+ TILEGX_R9_REGNUM,
+ TILEGX_R10_REGNUM,
+ TILEGX_R11_REGNUM,
+ TILEGX_R12_REGNUM,
+ TILEGX_R13_REGNUM,
+ TILEGX_R14_REGNUM,
+ TILEGX_R15_REGNUM,
+ TILEGX_R16_REGNUM,
+ TILEGX_R17_REGNUM,
+ TILEGX_R18_REGNUM,
+ TILEGX_R19_REGNUM,
+ TILEGX_R20_REGNUM,
+ TILEGX_R21_REGNUM,
+ TILEGX_R22_REGNUM,
+ TILEGX_R23_REGNUM,
+ TILEGX_R24_REGNUM,
+ TILEGX_R25_REGNUM,
+ TILEGX_R26_REGNUM,
+ TILEGX_R27_REGNUM,
+ TILEGX_R28_REGNUM,
+ TILEGX_R29_REGNUM,
+ TILEGX_R30_REGNUM,
+ TILEGX_R31_REGNUM,
+ TILEGX_R32_REGNUM,
+ TILEGX_R33_REGNUM,
+ TILEGX_R34_REGNUM,
+ TILEGX_R35_REGNUM,
+ TILEGX_R36_REGNUM,
+ TILEGX_R37_REGNUM,
+ TILEGX_R38_REGNUM,
+ TILEGX_R39_REGNUM,
+ TILEGX_R40_REGNUM,
+ TILEGX_R41_REGNUM,
+ TILEGX_R42_REGNUM,
+ TILEGX_R43_REGNUM,
+ TILEGX_R44_REGNUM,
+ TILEGX_R45_REGNUM,
+ TILEGX_R46_REGNUM,
+ TILEGX_R47_REGNUM,
+ TILEGX_R48_REGNUM,
+ TILEGX_R49_REGNUM,
+ TILEGX_R50_REGNUM,
+ TILEGX_R51_REGNUM,
+ TILEGX_R52_REGNUM,
+ TILEGX_TP_REGNUM,
+ TILEGX_SP_REGNUM,
+ TILEGX_LR_REGNUM,
+
+ TILEGX_SN_REGNUM,
+ TILEGX_NUM_EASY_REGS = TILEGX_SN_REGNUM, /* 56 */
+
+ TILEGX_IO0_REGNUM,
+ TILEGX_IO1_REGNUM,
+ TILEGX_US0_REGNUM,
+ TILEGX_US1_REGNUM,
+ TILEGX_US2_REGNUM,
+ TILEGX_US3_REGNUM,
+ TILEGX_ZERO_REGNUM,
+
+ TILEGX_PC_REGNUM,
+ TILEGX_NUM_PHYS_REGS = TILEGX_PC_REGNUM, /* 64 */
+
+ TILEGX_NUM_REGS /* 65 */
+ };
+
+enum { tilegx_reg_size = 8 };
+
+#endif /* tilegx-tdep.h */
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)
2012-05-30 19:56 ` Pedro Alves
@ 2012-05-30 20:09 ` Jeff Kenton
2012-05-31 8:53 ` [patch] Compilation regression on older gcc + 32-bit host [Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)] Jan Kratochvil
1 sibling, 0 replies; 16+ messages in thread
From: Jeff Kenton @ 2012-05-30 20:09 UTC (permalink / raw)
To: Pedro Alves; +Cc: Joel Brobecker, gdb-patches
On 05/30/2012 03:55 PM, Pedro Alves wrote:
> Hi Jeff,
>
> Please always send patches against the current mainline; the "tilegx_return_value"
> function had a function signature that is no longer correct in mainline, and thus
> caused an --enable-targets=all build to fail. I've fixed it.
>
> I've also went through the patch and updated a series of formatting
> issues (tabs/spaces, some alignments, etc.) and a few typos/pastos, as it was more
> efficient that more back and forth. ;-) I've also done a couple other minor
> things, like adding multiple inclusion guards to tilegx-tdep.h.
>
> Here's the patch as checked in.
>
>
Thank you.
--jeff kenton
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch] Compilation regression on older gcc + 32-bit host [Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)]
2012-05-30 19:56 ` Pedro Alves
2012-05-30 20:09 ` Jeff Kenton
@ 2012-05-31 8:53 ` Jan Kratochvil
2012-05-31 10:05 ` Pedro Alves
1 sibling, 1 reply; 16+ messages in thread
From: Jan Kratochvil @ 2012-05-31 8:53 UTC (permalink / raw)
To: Pedro Alves; +Cc: Jeff Kenton, Joel Brobecker, gdb-patches
On Wed, 30 May 2012 21:55:08 +0200, Pedro Alves wrote:
> Here's the patch as checked in.
>
> gdb/
> * Makefile.in (ALL_TARGET_OBJS): Add tilegx-tdep.o and
> tilegx-linux-tdep.o.
> (ALLDEPFILES): Add tilegx-linux-nat.c, tilegx-tdep.c and
> tilegx-linux-tdep.c.
> * configure.tgt: Handle tilegx-*-linux*.
> * tilegx-tdep.h: New file.
> * tilegx-tdep.c: New file.
> * tilegx-linux-tdep.c: New file.
> * regformats/reg-tilegx.dat: New file.
On CentOS i386 (gcc-4.4.6-3.el6.i686):
tilegx-linux-tdep.c:59: error: integer constant is too large for ‘long’ type
tilegx-linux-tdep.c:60: error: integer constant is too large for ‘long’ type
I would put there ULL for ULONGEST although there was recent discusssion 'long
long' is not acceptable. But sourceware tree already has large number of
'long long' uses:
$ egrep -ri '[0-9] *U?LL\>' .|egrep -v '/(opcodes|libdecnumber)/'|wc -l
303
$ egrep -ri '[0-9] *U?LL\>' .|wc -l
15734
So I find 'long long' is perfectly valid for Sourceware tree.
Still the "right" fix would be below.
I will check it in with ULL today if no comments appear.
Thanks,
Jan
gdb/
2012-05-31 Jan Kratochvil <jan.kratochvil@redhat.com>
* tilegx-linux-tdep.c (tilegx_l): Use UINT64_C.
--- ./gdb/tilegx-linux-tdep.c 30 May 2012 19:31:44 -0000 1.1
+++ ./gdb/tilegx-linux-tdep.c 31 May 2012 08:43:23 -0000
@@ -56,8 +56,8 @@ static const struct tramp_frame tilegx_l
SIGTRAMP_FRAME,
8,
{
- { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
- { 0x286b180051485000, -1 }, /* { swint1 } */
+ { UINT64_C (0x00045fe551483000), -1 }, /* { moveli r10, 139 } */
+ { UINT64_C (0x286b180051485000), -1 }, /* { swint1 } */
{ TRAMP_SENTINEL_INSN, -1 }
},
tilegx_linux_sigframe_init
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [patch] Compilation regression on older gcc + 32-bit host [Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)]
2012-05-31 8:53 ` [patch] Compilation regression on older gcc + 32-bit host [Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)] Jan Kratochvil
@ 2012-05-31 10:05 ` Pedro Alves
2012-05-31 15:40 ` [patch] Require long long for GDB [Re: [patch] Compilation regression on older gcc + 32-bit host] Jan Kratochvil
0 siblings, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-05-31 10:05 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Jeff Kenton, Joel Brobecker, gdb-patches
On 05/31/2012 09:52 AM, Jan Kratochvil wrote:
> On CentOS i386 (gcc-4.4.6-3.el6.i686):
>
> tilegx-linux-tdep.c:59: error: integer constant is too large for ‘long’ type
> tilegx-linux-tdep.c:60: error: integer constant is too large for ‘long’ type
>
> I would put there ULL for ULONGEST although there was recent discusssion 'long
> long' is not acceptable. But sourceware tree already has large number of
> 'long long' uses:
> $ egrep -ri '[0-9] *U?LL\>' .|egrep -v '/(opcodes|libdecnumber)/'|wc -l
> 303
Not quite. bfd's only use of "long long" in common code is guarded by HAVE_STRTOULL.
I can't find any unconditional long long use in the whole of binutils. opcodes
uses long long in many ports, but then there are many ports that don't use it. It's native
toolchains on those ports that could be problematic (old hosts with old, non-gcc compilers).
(People on such hosts wouldn't be using "--enable-targets=all", nor building cross toolchains).
You're right about libdecnumber. It takes care to not assume stdint.h is available, etc.,
but then uses long long / ull unconditionally. If I'm reading the code correctly,
any project that depends on libdecnumber is therefore already depending on long long
unconditionally too.
In any case, for gdb, I think it's now safe to assume that long long is available
on all supported hosts.
> So I find 'long long' is perfectly valid for Sourceware tree.
>
> Still the "right" fix would be below.
>
> I will check it in with ULL today if no comments appear.
LONGEST (the type of the field the constant in question is initializing) is defined like so:
#ifdef BFD64
#define LONGEST BFD_HOST_64_BIT
#define ULONGEST BFD_HOST_U_64_BIT
#else /* No BFD64 */
#ifdef CC_HAS_LONG_LONG
#define LONGEST long long
#define ULONGEST unsigned long long
#else
#ifdef BFD_HOST_64_BIT
/* BFD_HOST_64_BIT is defined for some hosts that don't have long long
(e.g. i386-windows) so try it. */
#define LONGEST BFD_HOST_64_BIT
#define ULONGEST BFD_HOST_U_64_BIT
#else
#define LONGEST long
#define ULONGEST unsigned long
#endif
#endif
and this means we're assuming the "#define LONGEST long"
is never reached nowaways, or that if it does, long is 64-bit.
That'd be fine with me.
It'd be super fine with the below as well, and it might even be better (stop
the non-fixed-sized types insanity). You should then change tramp_frame
to use uint64_t instead of ULONGEST, though.
> gdb/
> 2012-05-31 Jan Kratochvil <jan.kratochvil@redhat.com>
>
> * tilegx-linux-tdep.c (tilegx_l): Use UINT64_C.
>
> --- ./gdb/tilegx-linux-tdep.c 30 May 2012 19:31:44 -0000 1.1
> +++ ./gdb/tilegx-linux-tdep.c 31 May 2012 08:43:23 -0000
> @@ -56,8 +56,8 @@ static const struct tramp_frame tilegx_l
> SIGTRAMP_FRAME,
> 8,
> {
> - { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
> - { 0x286b180051485000, -1 }, /* { swint1 } */
> + { UINT64_C (0x00045fe551483000), -1 }, /* { moveli r10, 139 } */
> + { UINT64_C (0x286b180051485000), -1 }, /* { swint1 } */
> { TRAMP_SENTINEL_INSN, -1 }
> },
> tilegx_linux_sigframe_init
--
Pedro Alves
^ permalink raw reply [flat|nested] 16+ messages in thread
* [patch] Require long long for GDB [Re: [patch] Compilation regression on older gcc + 32-bit host]
2012-05-31 10:05 ` Pedro Alves
@ 2012-05-31 15:40 ` Jan Kratochvil
2012-06-01 14:45 ` [commit] Fix tilegx-linux-tdep.c compilation [Re: [patch] Require long long for GDB] Jan Kratochvil
0 siblings, 1 reply; 16+ messages in thread
From: Jan Kratochvil @ 2012-05-31 15:40 UTC (permalink / raw)
To: Pedro Alves; +Cc: Jeff Kenton, Joel Brobecker, gdb-patches
On Thu, 31 May 2012 12:04:48 +0200, Pedro Alves wrote:
> Not quite. bfd's only use of "long long" in common code is guarded by HAVE_STRTOULL.
> I can't find any unconditional long long use in the whole of binutils. opcodes
> uses long long in many ports, but then there are many ports that don't use it. It's native
> toolchains on those ports that could be problematic (old hosts with old, non-gcc compilers).
> (People on such hosts wouldn't be using "--enable-targets=all", nor building cross toolchains).
OK, thanks for the analysis.
> In any case, for gdb, I think it's now safe to assume that long long is available
> on all supported hosts.
+
> and this means we're assuming the "#define LONGEST long"
> is never reached nowaways, or that if it does, long is 64-bit.
OK, so I will check in this patch.
> It'd be super fine with the below as well, and it might even be better (stop
> the non-fixed-sized types insanity). You should then change tramp_frame
> to use uint64_t instead of ULONGEST, though.
And ULL afterwards.
Thanks,
Jan
gdb/
2012-05-31 Jan Kratochvil <jan.kratochvil@redhat.com>
* configure.ac (CC_HAS_LONG_LONG): Replace by AC_MSG_ERROR.
* defs.h (LONGEST, ULONGEST): Remove conditionalization for
CC_HAS_LONG_LONG.
* dwarf2-frame.c (DW64_CIE_ID): Likewise.
* printcmd.c (ui_printf): Remove conditionalizations for
CC_HAS_LONG_LONG.
* config.in: Regenerate.
* configure: Regenerate.
gdb/doc/
2012-05-31 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdbint.texinfo (Host Definition): Remove CC_HAS_LONG_LONG.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index d7409d0..dbf8dc0 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -1487,9 +1487,9 @@ AC_CACHE_CHECK([for long long support in compiler], gdb_cv_c_long_long,
[[switch (foo & 2) { case 0: return 1; }]])],
gdb_cv_c_long_long=yes,
gdb_cv_c_long_long=no)])
-if test $gdb_cv_c_long_long = yes; then
- AC_DEFINE(CC_HAS_LONG_LONG, 1,
- [Define to 1 if the compiler supports long long.])
+if test $gdb_cv_c_long_long != yes; then
+ # libdecnumber requires long long.
+ AC_MSG_ERROR([Compiler must support long long for GDB.])
fi
# Check if the compiler and runtime support printing long longs.
diff --git a/gdb/defs.h b/gdb/defs.h
index 03092aa..60b738e 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -120,20 +120,8 @@ typedef bfd_vma CORE_ADDR;
#else /* No BFD64 */
-#ifdef CC_HAS_LONG_LONG
#define LONGEST long long
#define ULONGEST unsigned long long
-#else
-#ifdef BFD_HOST_64_BIT
-/* BFD_HOST_64_BIT is defined for some hosts that don't have long long
- (e.g. i386-windows) so try it. */
-#define LONGEST BFD_HOST_64_BIT
-#define ULONGEST BFD_HOST_U_64_BIT
-#else
-#define LONGEST long
-#define ULONGEST unsigned long
-#endif
-#endif
#endif /* No BFD64 */
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index 01786ef..a99ef1e 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -1790,11 +1790,7 @@ add_fde (struct dwarf2_fde_table *fde_table, struct dwarf2_fde *fde)
fde_table->entries[fde_table->num_entries - 1] = fde;
}
-#ifdef CC_HAS_LONG_LONG
#define DW64_CIE_ID 0xffffffffffffffffULL
-#else
-#define DW64_CIE_ID ~0
-#endif
/* Defines the type of eh_frames that are expected to be decoded: CIE, FDE
or any of them. */
diff --git a/gdb/printcmd.c b/gdb/printcmd.c
index 030a4f2..8fee2cb 100644
--- a/gdb/printcmd.c
+++ b/gdb/printcmd.c
@@ -2499,7 +2499,7 @@ ui_printf (char *arg, struct ui_file *stream)
error (_("long double not supported in printf"));
#endif
case long_long_arg:
-#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+#ifdef PRINTF_HAS_LONG_LONG
{
long long val = value_as_long (val_args[i]);
@@ -2635,7 +2635,7 @@ ui_printf (char *arg, struct ui_file *stream)
handle %p as glibc would: %#x or a literal "(nil)". */
char *p, *fmt, *fmt_p;
-#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+#ifdef PRINTF_HAS_LONG_LONG
long long val = value_as_long (val_args[i]);
#else
long val = value_as_long (val_args[i]);
@@ -2670,7 +2670,7 @@ ui_printf (char *arg, struct ui_file *stream)
gdb_assert (*p == 'p' && *(p + 1) == '\0');
if (val != 0)
{
-#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+#ifdef PRINTF_HAS_LONG_LONG
*fmt_p++ = 'l';
#endif
*fmt_p++ = 'l';
diff --git a/gdb/config.in b/gdb/config.in
index a3bd8dd..b29a1d9 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -12,9 +12,6 @@
/* Directory of programs. */
#undef BINDIR
-/* Define to 1 if the compiler supports long long. */
-#undef CC_HAS_LONG_LONG
-
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
diff --git a/gdb/configure b/gdb/configure
index f638268..6f31786 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -11494,10 +11494,9 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gdb_cv_c_long_long" >&5
$as_echo "$gdb_cv_c_long_long" >&6; }
-if test $gdb_cv_c_long_long = yes; then
-
-$as_echo "#define CC_HAS_LONG_LONG 1" >>confdefs.h
-
+if test $gdb_cv_c_long_long != yes; then
+ # libdecnumber requires long long.
+ as_fn_error "Compiler must support long long for GDB." "$LINENO" 5
fi
# Check if the compiler and runtime support printing long longs.
@@ -12805,7 +12804,7 @@ $as_echo "could not find ${TCL_BIN_DIR}/tclConfig.sh" >&6; }
elif test "`uname -s`" = "Darwin"; then
# If Tcl was built as a framework, attempt to use the libraries
# from the framework at the given location so that linking works
- # against Tcl.framework installed in an arbitary location.
+ # against Tcl.framework installed in an arbitrary location.
case ${TCL_DEFS} in
*TCL_FRAMEWORK*)
if test -f "${TCL_BIN_DIR}/${TCL_LIB_FILE}"; then
@@ -12920,7 +12919,7 @@ $as_echo "could not find ${TK_BIN_DIR}/tkConfig.sh" >&6; }
elif test "`uname -s`" = "Darwin"; then
# If Tk was built as a framework, attempt to use the libraries
# from the framework at the given location so that linking works
- # against Tk.framework installed in an arbitary location.
+ # against Tk.framework installed in an arbitrary location.
case ${TK_DEFS} in
*TK_FRAMEWORK*)
if test -f "${TK_BIN_DIR}/${TK_LIB_FILE}"; then
diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo
index 267a6eb..3b9d8ed 100644
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -2770,11 +2770,6 @@ Substitute for isatty, if not available.
@item FOPEN_RB
Define this if binary files are opened the same way as text files.
-@item CC_HAS_LONG_LONG
-@cindex @code{long long} data type
-Define this if the host C compiler supports @code{long long}. This is set
-by the @code{configure} script.
-
@item PRINTF_HAS_LONG_LONG
Define this if the host can handle printing of long long integers via
the printf format conversion specifier @code{ll}. This is set by the
^ permalink raw reply [flat|nested] 16+ messages in thread
* [commit] Fix tilegx-linux-tdep.c compilation [Re: [patch] Require long long for GDB]
2012-05-31 15:40 ` [patch] Require long long for GDB [Re: [patch] Compilation regression on older gcc + 32-bit host] Jan Kratochvil
@ 2012-06-01 14:45 ` Jan Kratochvil
0 siblings, 0 replies; 16+ messages in thread
From: Jan Kratochvil @ 2012-06-01 14:45 UTC (permalink / raw)
To: Pedro Alves; +Cc: Jeff Kenton, Joel Brobecker, gdb-patches
On Thu, 31 May 2012 17:40:19 +0200, Jan Kratochvil wrote:
> And ULL afterwards.
Checked in.
Thanks,
Jan
http://sourceware.org/ml/gdb-cvs/2012-06/msg00002.html
--- src/gdb/ChangeLog 2012/05/31 22:07:29 1.14307
+++ src/gdb/ChangeLog 2012/06/01 14:43:27 1.14308
@@ -1,3 +1,7 @@
+2012-05-31 Jan Kratochvil <jan.kratochvil@redhat.com>
+
+ * tilegx-linux-tdep.c (tilegx_l): Use ULL for 64-bit values.
+
2012-05-31 Edjunior Machado <emachado@linux.vnet.ibm.com>
* ppc-linux-nat.c (have_ptrace_booke_interface): Disable ptrace
--- src/gdb/tilegx-linux-tdep.c 2012/05/30 19:31:44 1.1
+++ src/gdb/tilegx-linux-tdep.c 2012/06/01 14:43:30 1.2
@@ -56,8 +56,8 @@
SIGTRAMP_FRAME,
8,
{
- { 0x00045fe551483000, -1 }, /* { moveli r10, 139 } */
- { 0x286b180051485000, -1 }, /* { swint1 } */
+ { 0x00045fe551483000ULL, -1 }, /* { moveli r10, 139 } */
+ { 0x286b180051485000ULL, -1 }, /* { swint1 } */
{ TRAMP_SENTINEL_INSN, -1 }
},
tilegx_linux_sigframe_init
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2012-06-01 14:45 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-11 16:09 [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb) Jeff Kenton
2012-05-14 16:21 ` Joel Brobecker
2012-05-21 14:23 ` Jeff Kenton
2012-05-23 17:34 ` Pedro Alves
2012-05-24 19:26 ` Jeff Kenton
2012-05-25 15:17 ` Pedro Alves
2012-05-29 15:24 ` Jeff Kenton
2012-05-30 19:56 ` Pedro Alves
2012-05-30 20:09 ` Jeff Kenton
2012-05-31 8:53 ` [patch] Compilation regression on older gcc + 32-bit host [Re: [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb)] Jan Kratochvil
2012-05-31 10:05 ` Pedro Alves
2012-05-31 15:40 ` [patch] Require long long for GDB [Re: [patch] Compilation regression on older gcc + 32-bit host] Jan Kratochvil
2012-06-01 14:45 ` [commit] Fix tilegx-linux-tdep.c compilation [Re: [patch] Require long long for GDB] Jan Kratochvil
2012-05-29 15:24 ` [PATCH] Add support for Tilera TILE-Gx processor (part 1/3: gdb) Jeff Kenton
2012-05-29 17:11 ` Jeff Kenton
2012-05-14 16:24 ` Joel Brobecker
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox