* [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
@ 2012-04-19 20:18 Jeff Kenton
2012-04-20 15:18 ` Yao Qi
2012-04-20 19:05 ` Tom Tromey
0 siblings, 2 replies; 13+ messages in thread
From: Jeff Kenton @ 2012-04-19 20:18 UTC (permalink / raw)
To: gdb-patches
[PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
This is a port of GDB to the Tilera TILE-Gx processor.
I broke this into 2 parts: the first contains changes to existing
configure and Makefiles. Changes are based on the gdb-7.4.50.20120410
snapshot. The second (this part) contains new Tilera specific files.
Comments please.
Thanks.
jeff kenton (jkenton@tilera.com)
diff -r -u -N ./gdb-7.4.50.20120410/gdb/config/tilegx/nm-linux.h
./gdb/config/tilegx/nm-linux.h
--- ./gdb-7.4.50.20120410/gdb/config/tilegx/nm-linux.h 1969-12-31
19:00:00.000000000 -0500
+++ ./gdb/config/tilegx/nm-linux.h 2012-04-19 13:55:56.195492000 -0400
@@ -0,0 +1,45 @@
+/* Native-dependent definitions for GNU/Linux on TILE.
+
+ Copyright (C) 1986-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"
+
+/* Return sizeof user struct to callers in less machine dependent
+ routines. Hard coded for cross-compilation friendliness. */
+
+#define KERNEL_U_SIZE 308
+
+/* This is the amount to substract from u.u_ar0 to get the offset in
+ the core file of the register values. */
+#define KERNEL_U_ADDR 0
+
+/* ptrace register ``addresses'' are absolute. */
+
+#define U_REGS_OFFSET 0
+
+/* ptrace transfers longs, and expects addresses as longs. */
+
+#define PTRACE_ARG3_TYPE long
+#define PTRACE_XFER_TYPE long
+
+#endif /* NM_TILELINUX_H */
diff -r -u -N ./gdb-7.4.50.20120410/gdb/config/tilegx/tilegx.mh
./gdb/config/tilegx/tilegx.mh
--- ./gdb-7.4.50.20120410/gdb/config/tilegx/tilegx.mh 1969-12-31
19:00:00.000000000 -0500
+++ ./gdb/config/tilegx/tilegx.mh 2012-04-19 13:55:56.214487000 -0400
@@ -0,0 +1,12 @@
+# Host: Tilera tilegx running GNU/Linux.
+
+NAT_FILE= nm-linux.h
+NATDEPFILES= inf-ptrace.o fork-child.o \
+ tilegx-linux-nat.o \
+ proc-service.o linux-thread-db.o \
+ linux-nat.o linux-osdata.o linux-fork.o \
+ linux-procfs.o linux-ptrace.o
+
+# The dynamically loaded libthread_db needs access to symbols in the
+# gdb executable.
+LOADLIBES = -ldl -rdynamic
diff -r -u -N ./gdb-7.4.50.20120410/gdb/config/tilegx/tm-linux.h
./gdb/config/tilegx/tm-linux.h
--- ./gdb-7.4.50.20120410/gdb/config/tilegx/tm-linux.h 1969-12-31
19:00:00.000000000 -0500
+++ ./gdb/config/tilegx/tm-linux.h 2012-04-19 13:55:56.233503000 -0400
@@ -0,0 +1,32 @@
+/* Target-dependent definitions for GNU/Linux TILE.
+
+ Copyright (C) 1986-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 TM_TILELINUX_H
+#define TM_TILELINUX_H
+
+/* Pull in GNU/Linux generic defs. */
+#include "config/tm-linux.h"
+
+/* Integer capable of holding an instruction bundle. */
+typedef unsigned long long t_bundle;
+
+/* We do single stepping in ptrace. */
+/* (which looks like hardware rather than software). */
+
+#endif /* TM_TILELINUX_H */
diff -r -u -N ./gdb-7.4.50.20120410/gdb/gdbserver/linux-tile-low.c
./gdb/gdbserver/linux-tile-low.c
--- ./gdb-7.4.50.20120410/gdb/gdbserver/linux-tile-low.c
1969-12-31 19:00:00.000000000 -0500
+++ ./gdb/gdbserver/linux-tile-low.c 2012-04-19 13:55:56.328492000 -0400
@@ -0,0 +1,123 @@
+#include "server.h"
+#include "linux-low.h"
+
+#include <sys/ptrace.h>
+
+/* Defined in auto-generated file reg-tile.c. */
+void init_registers_tile (void);
+
+#define tile_num_regs 65
+
+static int tile_regmap[] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 56
+};
+
+static int
+tile_cannot_fetch_register (int regno)
+{
+ if (regno >= 0 && regno < 56)
+ return 0;
+ else if (regno == 64)
+ return 0;
+ else
+ return 1;
+}
+
+static int
+tile_cannot_store_register (int regno)
+{
+ if (regno >= 0 && regno < 56)
+ return 0;
+ else if (regno == 64)
+ return 0;
+ else
+ return 1;
+}
+
+static CORE_ADDR
+tile_get_pc (struct regcache *regcache)
+{
+ unsigned long pc;
+ collect_register_by_name (regcache, "pc", &pc);
+ return pc;
+}
+
+static void
+tile_set_pc (struct regcache *regcache, CORE_ADDR pc)
+{
+ unsigned long newpc = pc;
+ supply_register_by_name (regcache, "pc", &newpc);
+}
+
+static unsigned long long tile_breakpoint = 0x400b3cae70166000ULL;
+#define tile_breakpoint_len 8
+
+static int
+tile_breakpoint_at (CORE_ADDR where)
+{
+ unsigned long long insn;
+
+ (*the_target->read_memory) (where, (unsigned char *) &insn, 8);
+ if (insn == tile_breakpoint)
+ return 1;
+
+ /* If necessary, recognize more trap instructions here. GDB only
uses the
+ one. */
+ return 0;
+}
+
+static void
+tile_fill_gregset (struct regcache *regcache, void *buf)
+{
+ int i;
+
+ for (i = 0; i < tile_num_regs; i++)
+ if (tile_regmap[i] != -1)
+ collect_register (regcache, i, ((unsigned int *) buf) +
tile_regmap[i]);
+}
+
+static void
+tile_store_gregset (struct regcache *regcache, const void *buf)
+{
+ int i;
+ char zerobuf[8];
+
+ memset (zerobuf, 0, 8);
+ for (i = 0; i < tile_num_regs; i++)
+ if (tile_regmap[i] != -1)
+ supply_register (regcache, i, ((unsigned long *) buf) +
tile_regmap[i]);
+ else
+ supply_register (regcache, i, zerobuf);
+}
+
+struct regset_info target_regsets[] = {
+ { PTRACE_GETREGS, PTRACE_SETREGS, 0, tile_num_regs * 4,
+ GENERAL_REGS, tile_fill_gregset, tile_store_gregset },
+ { 0, 0, 0, -1, -1, NULL, NULL }
+};
+
+struct linux_target_ops the_low_target = {
+ init_registers_tile,
+ tile_num_regs,
+ tile_regmap,
+ NULL,
+ tile_cannot_fetch_register,
+ tile_cannot_store_register,
+ NULL,
+ tile_get_pc,
+ tile_set_pc,
+ (const unsigned char *) &tile_breakpoint,
+ tile_breakpoint_len,
+ NULL,
+ 0,
+ tile_breakpoint_at,
+};
diff -r -u -N ./gdb-7.4.50.20120410/gdb/regformats/reg-tilegx.dat
./gdb/regformats/reg-tilegx.dat
--- ./gdb-7.4.50.20120410/gdb/regformats/reg-tilegx.dat 1969-12-31
19:00:00.000000000 -0500
+++ ./gdb/regformats/reg-tilegx.dat 2012-04-19 13:55:56.356493000 -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 ./gdb-7.4.50.20120410/gdb/tilegx-linux-nat.c
./gdb/tilegx-linux-nat.c
--- ./gdb-7.4.50.20120410/gdb/tilegx-linux-nat.c 1969-12-31
19:00:00.000000000 -0500
+++ ./gdb/tilegx-linux-nat.c 2012-04-19 13:55:56.376489000 -0400
@@ -0,0 +1,188 @@
+/* Native-dependent code for GNU/Linux Tile
+
+ Copyright (C) 1986-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 "inferior.h"
+#include "gdbcore.h"
+#include "regcache.h"
+#include "linux-nat.h"
+
+#include <sys/ptrace.h>
+
+#include "gdb_assert.h"
+#include "gdb_string.h"
+#include "nm-linux.h"
+
+#include <sys/procfs.h>
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+/* Defines ps_err_e, struct ps_prochandle. */
+#include "gdb_proc_service.h"
+
+
+/* The register sets used in GNU/Linux ELF core-dumps are identical to
+ the register sets in `struct user' that is used for a.out
+ core-dumps, and is also used by `ptrace'. The corresponding types
+ are `elf_gregset_t' for the general-purpose registers (with
+ `elf_greg_t' the type of a single GP register) and `elf_fpregset_t'
+ for the floating-point registers.
+
+ Those types used to be available under the names `gregset_t' and
+ `fpregset_t' too, and this file used those names in the past. But
+ those names are now used for the register sets used in the
+ `mcontext_t' type, and have a different size and layout. */
+
+/* Mapping between the general-purpose registers in `struct user'
+ format and GDB's register array layout. Note that we map the
+ first 56 registers (0 thru 55) one-to-one. GDB maps the pc to
+ slot 64, but ptrace returns it in slot 56. */
+static const int regmap[] =
+{
+ 0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 56
+};
+
+
+/* Transfering the general-purpose registers between GDB, inferiors
+ and core files. */
+
+/* Fill GDB's register array with the general-purpose register values
+ in *GREGSETP. */
+
+void
+supply_gregset (struct regcache* regcache,
+ const elf_gregset_t *gregsetp)
+{
+ elf_greg_t *regp = (elf_greg_t *) gregsetp;
+ int i;
+
+ for (i = 0; i < sizeof(regmap)/sizeof(regmap[0]); i++)
+ if (regmap[i] >= 0)
+ regcache_raw_supply (regcache, i, regp + regmap[i]);
+}
+
+/* Fill registers in *GREGSETPS with the values in GDB's
+ register array. */
+
+void
+fill_gregset (const struct regcache* regcache,
+ elf_gregset_t *gregsetp, int regno)
+{
+ elf_greg_t *regp = (elf_greg_t *) gregsetp;
+ int i;
+
+ for (i = 0; i < sizeof(regmap)/sizeof(regmap[0]); i++)
+ if (regmap[i] >= 0)
+ regcache_raw_collect (regcache, i, regp + regmap[i]);
+}
+
+/* Transfering floating-point registers between GDB, inferiors and
cores. */
+
+/* Fill GDB's register array with the floating-point register values in
+ *FPREGSETP. */
+
+void
+supply_fpregset (struct regcache *regcache,
+ const elf_fpregset_t *fpregsetp)
+{
+ /* NOTE: There are no floating-point registers for TILE-Gx. */
+}
+
+/* Fill register REGNO (if it is a floating-point register) in
+ *FPREGSETP with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_fpregset (const struct regcache *regcache,
+ elf_fpregset_t *fpregsetp, int regno)
+{
+ /* NOTE: There are no floating-point registers for TILE-Gx. */
+}
+
+
+/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
+ for all registers. */
+
+static void
+fetch_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ elf_gregset_t regs;
+ int tid;
+
+ tid = ptid_get_lwp (inferior_ptid);
+ if (tid == 0)
+ tid = ptid_get_pid (inferior_ptid);
+
+ if (ptrace (PTRACE_GETREGS, tid, 0, (PTRACE_TYPE_ARG3) ®s) < 0)
+ perror_with_name (_("Couldn't get registers"));
+
+ supply_gregset (regcache, (const elf_gregset_t *)®s);
+}
+
+/* Store register REGNUM back into the inferior. If REGNUM is -1, do
+ this for all registers. */
+
+static void
+store_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ elf_gregset_t regs;
+ int tid;
+
+ tid = ptid_get_lwp (inferior_ptid);
+ if (tid == 0)
+ tid = ptid_get_pid (inferior_ptid);
+
+ if (ptrace (PTRACE_GETREGS, tid, 0, (PTRACE_TYPE_ARG3) ®s) < 0)
+ perror_with_name (_("Couldn't get registers"));
+
+ fill_gregset (regcache, ®s, regnum);
+
+ if (ptrace (PTRACE_SETREGS, tid, 0, (PTRACE_TYPE_ARG3) ®s) < 0)
+ perror_with_name (_("Couldn't write registers"));
+}
+
+
+void _initialize_tile_linux_nat (void);
+
+void
+_initialize_tile_linux_nat (void)
+{
+ struct target_ops *t;
+
+ /* Fill in the generic GNU/Linux methods. */
+ t = linux_target ();
+
+ /* Add our register access methods. */
+ t->to_fetch_registers = fetch_inferior_registers;
+ t->to_store_registers = store_inferior_registers;
+
+ /* Register the target. */
+ linux_nat_add_target (t);
+}
diff -r -u -N ./gdb-7.4.50.20120410/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
--- ./gdb-7.4.50.20120410/gdb/tilegx-tdep.c 1969-12-31
19:00:00.000000000 -0500
+++ ./gdb/tilegx-tdep.c 2012-04-19 14:41:19.259375000 -0400
@@ -0,0 +1,1201 @@
+/* Target-dependent code for the Tilera TILE-Gx processor.
+
+ Copyright (C) 1986-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 "objfiles.h"
+#include "solib-svr4.h"
+#include "symtab.h"
+
+#include "../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;
+};
+
+/* ISSUE: Shouldn't the last entry have "0" as its "value"? */
+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 };
+
+/* Function: tilegx_register_name
+ Returns the name of the standard TILE-Gx register N. */
+
+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];
+}
+
+static struct type *
+tilegx_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ return builtin_type (gdbarch)->builtin_uint64;
+}
+
+static int
+tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
+{
+ return num;
+}
+
+
+/* Function: tilegx_type_is_scalar
+ Makes the decision if a given type is a scalar types. 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);
+}
+
+/* Function: tilegx_use_struct_convention
+ 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 contexts of the "return" command, and of
+ 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);
+}
+
+/* Function: tilegx_extract_return_value
+ 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);
+}
+
+/* Function: tilegx_store_return_value
+ 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;
+}
+
+
+/* Function: tilegx_push_dummy_call
+ 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 remaining 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 (CORE_ADDR start_addr, CORE_ADDR end_addr,
+ struct tilegx_frame_cache *cache,
+ struct frame_info *next_frame)
+{
+ CORE_ADDR next_addr;
+ CORE_ADDR prolog_end = end_addr;
+ ULONGEST inst, inst2;
+ LONGEST offset;
+ int regnum;
+ char 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 = bfd_getl64(&instbuf[next_addr - instbuf_start]);
+
+ num_insns = parse_insn_tilegx(bundle, next_addr, decoded);
+
+ for (i = 0; i < num_insns; i++)
+ {
+ struct tilegx_decoded_instruction *this_insn = &decoded[i];
+ long long *operands = 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. */
+ unsigned long long 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;
+}
+
+/* Function: tilegx_skip_prologue
+ 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 (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)
+{
+ /* ISSUE: Who calls this function? */
+
+ 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)];
+ static char breakpoint_initialized = 0;
+ if (!breakpoint_initialized)
+ {
+ tilegx_bundle_bits bits = TILEGX_BPT_BUNDLE;
+ unsigned int i;
+ for (i = 0; i < sizeof(breakpoint); i++)
+ {
+ breakpoint[i] = (unsigned char)bits;
+ bits >>= 8;
+ }
+ breakpoint_initialized = 1;
+ }
+ *lenptr = sizeof (breakpoint);
+ return breakpoint;
+}
+
+
+/* ISSUE: Does this need an implementation?
+ NOTE: This function is called by "handle_inferior_event", when stepping
+ into a subroutine, but NOT a PLT stub (as that is handled
specially). */
+static CORE_ADDR
+tilegx_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+ return 0;
+}
+
+
+/* For now, we'll just do a direct translation, but soon we may
+ * include an ASID and/or tilegx field in addresses, which doesn't
+ * appear in pointers -- so we need to keep the translation
+ * function around.
+ */
+
+static CORE_ADDR
+tilegx_pointer_to_address (struct gdbarch *gdbarch,
+ struct type *type, const gdb_byte *buf)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ return extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order);
+}
+
+static void
+tilegx_address_to_pointer (struct gdbarch *gdbarch,
+ struct type *type, gdb_byte *buf, CORE_ADDR
addr)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order, addr);
+}
+
+/* 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 (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;
+}
+
+
+/* Function: tilegx_gdbarch_init
+ 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_address_to_pointer (gdbarch, tilegx_address_to_pointer);
+ set_gdbarch_pointer_to_address (gdbarch, tilegx_pointer_to_address);
+
+ 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_skip_trampoline_code (gdbarch, tilegx_skip_trampoline_code);
+
+ 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;
+}
+
+static void
+tilegx_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+ /* We may not need anything here, but I think we need the function. */
+}
+
+
+/* Function: _initialize_tilegx_tdep
+ 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)
+{
+ /* tile-sim is so slow it needs a longer timeout. */
+ remote_timeout = 60;
+
+ register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
+
+ gdbarch_register_osabi (bfd_arch_tilegx, 0, GDB_OSABI_LINUX,
tilegx_init_abi);
+}
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-19 20:18 [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb) Jeff Kenton
@ 2012-04-20 15:18 ` Yao Qi
2012-04-20 15:30 ` Jeff Kenton
2012-04-23 15:05 ` Jeff Kenton
2012-04-20 19:05 ` Tom Tromey
1 sibling, 2 replies; 13+ messages in thread
From: Yao Qi @ 2012-04-20 15:18 UTC (permalink / raw)
To: Jeff Kenton; +Cc: gdb-patches
On 04/20/2012 03:25 AM, Jeff Kenton wrote:
>
I don't know tile-gx process at all, but some comments on code style.
>
> diff -r -u -N ./gdb-7.4.50.20120410/gdb/config/tilegx/nm-linux.h
> ./gdb/config/tilegx/nm-linux.h
> --- ./gdb-7.4.50.20120410/gdb/config/tilegx/nm-linux.h 1969-12-31
> 19:00:00.000000000 -0500
> +++ ./gdb/config/tilegx/nm-linux.h 2012-04-19 13:55:56.195492000 -0400
> @@ -0,0 +1,45 @@
> +/* Native-dependent definitions for GNU/Linux on TILE.
> +
> + Copyright (C) 1986-2012 Free Software Foundation, Inc.
^^^^^^^^^ 2012.
This is a new file, and created in 2012, so it should be "2012" only.
Here and other places.
> diff -r -u -N ./gdb-7.4.50.20120410/gdb/config/tilegx/tm-linux.h
> ./gdb/config/tilegx/tm-linux.h
> --- ./gdb-7.4.50.20120410/gdb/config/tilegx/tm-linux.h 1969-12-31
> 19:00:00.000000000 -0500
> +++ ./gdb/config/tilegx/tm-linux.h 2012-04-19 13:55:56.233503000 -0400
> @@ -0,0 +1,32 @@
> +/* Target-dependent definitions for GNU/Linux TILE.
> +
> + Copyright (C) 1986-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 TM_TILELINUX_H
> +#define TM_TILELINUX_H
> +
> +/* Pull in GNU/Linux generic defs. */
> +#include "config/tm-linux.h"
> +
> +/* Integer capable of holding an instruction bundle. */
> +typedef unsigned long long t_bundle;
> +
> +/* We do single stepping in ptrace. */
> +/* (which looks like hardware rather than software). */
What is this?
> +
> +#endif /* TM_TILELINUX_H */
> diff -r -u -N ./gdb-7.4.50.20120410/gdb/gdbserver/linux-tile-low.c
> ./gdb/gdbserver/linux-tile-low.c
> --- ./gdb-7.4.50.20120410/gdb/gdbserver/linux-tile-low.c
> 1969-12-31 19:00:00.000000000 -0500
> +++ ./gdb/gdbserver/linux-tile-low.c 2012-04-19 13:55:56.328492000 -0400
> @@ -0,0 +1,123 @@
> +#include "server.h"
> +#include "linux-low.h"
> +
> +#include <sys/ptrace.h>
> +
> +/* Defined in auto-generated file reg-tile.c. */
> +void init_registers_tile (void);
> +
> +#define tile_num_regs 65
> +
> +static int tile_regmap[] =
> +{
> + 0, 1, 2, 3, 4, 5, 6, 7,
> + 8, 9, 10, 11, 12, 13, 14, 15,
> + 16, 17, 18, 19, 20, 21, 22, 23,
> + 24, 25, 26, 27, 28, 29, 30, 31,
> + 32, 33, 34, 35, 36, 37, 38, 39,
> + 40, 41, 42, 43, 44, 45, 46, 47,
> + 48, 49, 50, 51, 52, 53, 54, 55,
> + -1, -1, -1, -1, -1, -1, -1, -1,
> + 56
> +};
> +
> +static int
> +tile_cannot_fetch_register (int regno)
> +{
> + if (regno >= 0 && regno < 56)
> + return 0;
> + else if (regno == 64)
> + return 0;
> + else
> + return 1;
> +}
> +
> +static int
> +tile_cannot_store_register (int regno)
> +{
> + if (regno >= 0 && regno < 56)
> + return 0;
> + else if (regno == 64)
> + return 0;
> + else
> + return 1;
> +}
> +
> +static CORE_ADDR
> +tile_get_pc (struct regcache *regcache)
> +{
> + unsigned long pc;
Need a blank line here.
> + collect_register_by_name (regcache, "pc", &pc);
> + return pc;
> +}
> +
> +static void
> +tile_set_pc (struct regcache *regcache, CORE_ADDR pc)
> +{
> + unsigned long newpc = pc;
and here.
> + supply_register_by_name (regcache, "pc", &newpc);
> +}
> +
> +static unsigned long long tile_breakpoint = 0x400b3cae70166000ULL;
> +#define tile_breakpoint_len 8
> +
> +static int
> +tile_breakpoint_at (CORE_ADDR where)
> +{
> + unsigned long long insn;
> +
Looks like sized type `uint64_t' may be better here for `insn'.
> + (*the_target->read_memory) (where, (unsigned char *) &insn, 8);
> + if (insn == tile_breakpoint)
> + return 1;
> +
> + /* If necessary, recognize more trap instructions here. GDB only
> uses the
> + one. */
> + return 0;
> +}
> +
> +static void
> +tile_fill_gregset (struct regcache *regcache, void *buf)
> +{
> + int i;
> +
> + for (i = 0; i < tile_num_regs; i++)
> + if (tile_regmap[i] != -1)
> + collect_register (regcache, i, ((unsigned int *) buf) +
> tile_regmap[i]);
> +}
> +
> +
> +struct regset_info target_regsets[] = {
> + { PTRACE_GETREGS, PTRACE_SETREGS, 0, tile_num_regs * 4,
> + GENERAL_REGS, tile_fill_gregset, tile_store_gregset },
> + { 0, 0, 0, -1, -1, NULL, NULL }
> +};
> +
> +struct linux_target_ops the_low_target = {
> + init_registers_tile,
> + tile_num_regs,
> + tile_regmap,
> + NULL,
> + tile_cannot_fetch_register,
> + tile_cannot_store_register,
> + NULL,
> + tile_get_pc,
> + tile_set_pc,
> + (const unsigned char *) &tile_breakpoint,
> + tile_breakpoint_len,
> + NULL,
> + 0,
> + tile_breakpoint_at,
> +};
> diff -r -u -N ./gdb-7.4.50.20120410/gdb/tilegx-linux-nat.c
> ./gdb/tilegx-linux-nat.c
> --- ./gdb-7.4.50.20120410/gdb/tilegx-linux-nat.c 1969-12-31
> 19:00:00.000000000 -0500
> +++ ./gdb/tilegx-linux-nat.c 2012-04-19 13:55:56.376489000 -0400
> @@ -0,0 +1,188 @@
> +/* Native-dependent code for GNU/Linux Tile
> +
> + Copyright (C) 1986-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 "inferior.h"
> +#include "gdbcore.h"
> +#include "regcache.h"
> +#include "linux-nat.h"
> +
> +#include <sys/ptrace.h>
> +
> +#include "gdb_assert.h"
> +#include "gdb_string.h"
> +#include "nm-linux.h"
> +
> +#include <sys/procfs.h>
> +
> +/* Prototypes for supply_gregset etc. */
> +#include "gregset.h"
> +
> +/* Defines ps_err_e, struct ps_prochandle. */
> +#include "gdb_proc_service.h"
> +
> +
> +/* The register sets used in GNU/Linux ELF core-dumps are identical to
> + the register sets in `struct user' that is used for a.out
> + core-dumps, and is also used by `ptrace'. The corresponding types
> + are `elf_gregset_t' for the general-purpose registers (with
> + `elf_greg_t' the type of a single GP register) and `elf_fpregset_t'
> + for the floating-point registers.
> +
> + Those types used to be available under the names `gregset_t' and
> + `fpregset_t' too, and this file used those names in the past. But
> + those names are now used for the register sets used in the
> + `mcontext_t' type, and have a different size and layout. */
> +
> +/* Mapping between the general-purpose registers in `struct user'
> + format and GDB's register array layout. Note that we map the
> + first 56 registers (0 thru 55) one-to-one. GDB maps the pc to
> + slot 64, but ptrace returns it in slot 56. */
> +static const int regmap[] =
> +{
> + 0, 1, 2, 3, 4, 5, 6, 7,
> + 8, 9, 10, 11, 12, 13, 14, 15,
> + 16, 17, 18, 19, 20, 21, 22, 23,
> + 24, 25, 26, 27, 28, 29, 30, 31,
> + 32, 33, 34, 35, 36, 37, 38, 39,
> + 40, 41, 42, 43, 44, 45, 46, 47,
> + 48, 49, 50, 51, 52, 53, 54, 55,
> + -1, -1, -1, -1, -1, -1, -1, -1,
> + 56
> +};
> +
> +
> +/* Transfering the general-purpose registers between GDB, inferiors
> + and core files. */
> +
> +/* Fill GDB's register array with the general-purpose register values
s> + in *GREGSETP. */
> +
> +void
> +supply_gregset (struct regcache* regcache,
> + const elf_gregset_t *gregsetp)
Can be `static'? Function name "tilegx_supply_gregset" is better.
> +{
> + elf_greg_t *regp = (elf_greg_t *) gregsetp;
> + int i;
> +
> + for (i = 0; i < sizeof(regmap)/sizeof(regmap[0]); i++)
> + if (regmap[i] >= 0)
> + regcache_raw_supply (regcache, i, regp + regmap[i]);
> +}
> +
> +/* Fill registers in *GREGSETPS with the values in GDB's
> + register array. */
> +
> +void
> +fill_gregset (const struct regcache* regcache,
> + elf_gregset_t *gregsetp, int regno)
Likewise.
> +{
> + elf_greg_t *regp = (elf_greg_t *) gregsetp;
> + int i;
> +
> + for (i = 0; i < sizeof(regmap)/sizeof(regmap[0]); i++)
> + if (regmap[i] >= 0)
> + regcache_raw_collect (regcache, i, regp + regmap[i]);
> +}
> +
> +/* Transfering floating-point registers between GDB, inferiors and
> cores. */
> +
> +/* Fill GDB's register array with the floating-point register values in
> + *FPREGSETP. */
> +
> +void
> +supply_fpregset (struct regcache *regcache,
> + const elf_fpregset_t *fpregsetp)
Likewise.
> +{
> + /* NOTE: There are no floating-point registers for TILE-Gx. */
> +}
> +
> +/* Fill register REGNO (if it is a floating-point register) in
> + *FPREGSETP with the value in GDB's register array. If REGNO is -1,
> + do this for all registers. */
> +
> +void
> +fill_fpregset (const struct regcache *regcache,
> + elf_fpregset_t *fpregsetp, int regno)
Likewise.
> +{
> + /* NOTE: There are no floating-point registers for TILE-Gx. */
> +}
> +
> +
> +/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
> + for all registers. */
> +
> +static void
> +fetch_inferior_registers (struct target_ops *ops,
> + struct regcache *regcache, int regnum)
> +{
> + elf_gregset_t regs;
> + int tid;
> +
> + tid = ptid_get_lwp (inferior_ptid);
> + if (tid == 0)
> + tid = ptid_get_pid (inferior_ptid);
> +
> + if (ptrace (PTRACE_GETREGS, tid, 0, (PTRACE_TYPE_ARG3) ®s) < 0)
> + perror_with_name (_("Couldn't get registers"));
> +
> + supply_gregset (regcache, (const elf_gregset_t *)®s);
> +}
> +
> +/* Store register REGNUM back into the inferior. If REGNUM is -1, do
> + this for all registers. */
> +
> +static void
> +store_inferior_registers (struct target_ops *ops,
> + struct regcache *regcache, int regnum)
> +{
> + elf_gregset_t regs;
> + int tid;
> +
> + tid = ptid_get_lwp (inferior_ptid);
> + if (tid == 0)
> + tid = ptid_get_pid (inferior_ptid);
> +
> + if (ptrace (PTRACE_GETREGS, tid, 0, (PTRACE_TYPE_ARG3) ®s) < 0)
> + perror_with_name (_("Couldn't get registers"));
> +
> + fill_gregset (regcache, ®s, regnum);
> +
> + if (ptrace (PTRACE_SETREGS, tid, 0, (PTRACE_TYPE_ARG3) ®s) < 0)
> + perror_with_name (_("Couldn't write registers"));
> +}
> +
> +
> +void _initialize_tile_linux_nat (void);
> +
extern initialize_file_ftype _initialize_tile_linux_nat;
> +void
> +_initialize_tile_linux_nat (void)
> +{
> + struct target_ops *t;
> +
> + /* Fill in the generic GNU/Linux methods. */
> + t = linux_target ();
> +
> + /* Add our register access methods. */
> + t->to_fetch_registers = fetch_inferior_registers;
> + t->to_store_registers = store_inferior_registers;
> +
> + /* Register the target. */
> + linux_nat_add_target (t);
> +}
> diff -r -u -N ./gdb-7.4.50.20120410/gdb/tilegx-tdep.c ./gdb/tilegx-tdep.c
> --- ./gdb-7.4.50.20120410/gdb/tilegx-tdep.c 1969-12-31
> 19:00:00.000000000 -0500
> +++ ./gdb/tilegx-tdep.c 2012-04-19 14:41:19.259375000 -0400
> @@ -0,0 +1,1201 @@
> +/* Target-dependent code for the Tilera TILE-Gx processor.
> +
> + Copyright (C) 1986-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/>. */
> +
> +
> +
> +enum { tilegx_reg_size = 8 };
> +
> +/* Function: tilegx_register_name
> + Returns the name of the standard TILE-Gx register N. */
> +
Usually, the comment of gdbarch hook method is in this style:
"/* 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)
> +{
> + return builtin_type (gdbarch)->builtin_uint64;
Don't we handle register PC here? Usually, the type of PC register
should be builtin_func_ptr.
> +}
> +
> +static int
> +tilegx_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num)
> +{
> + return num;
> +}
> +
> +
> +/* Function: tilegx_type_is_scalar
This line of comment is unnecessary. Here and other places.
> + Makes the decision if a given type is a scalar types. 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);
^^
Indentation looks incorrect.
> +}
> +
> +/* Function: tilegx_use_struct_convention
> + 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 contexts of the "return" command, and of
> + 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);
Indentation is incorrect.
> +}
> +
> +/* Function: tilegx_extract_return_value
> + 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);
> +}
> +
> +/* Function: tilegx_store_return_value
> + 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];
A blank line is needed here.
> + 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);
> + }
> +}
> +
> +
> +
> +
> +/* Function: tilegx_push_dummy_call
> + 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);
> + }
"{" and "}" is not needed.
> +
> + /* 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);
> + }
I am wondering if this loop is necessary. Usually, if the length of a
type exceeds 8, it will be passed by reference. If your ABI is similar,
"typelen" should be less than or equal to 8, and this loop is not needed.
> + }
> +
> + /* Align SP. */
> + stack_dest = tilegx_frame_align (gdbarch, stack_dest);
> +
> + /* Loop backwards through remaining arguments to determine stack
> alignment */
^ Missing ".".
> + 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;
> +}
> +
> +
> +
> +/* 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)
> +{
> + /* ISSUE: Who calls this function? */
> +
It is called through gdbarch_in_function_epilogue_p.
> + 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)];
> + static char breakpoint_initialized = 0;
> + if (!breakpoint_initialized)
> + {
> + tilegx_bundle_bits bits = TILEGX_BPT_BUNDLE;
> + unsigned int i;
> + for (i = 0; i < sizeof(breakpoint); i++)
> + {
> + breakpoint[i] = (unsigned char)bits;
> + bits >>= 8;
> + }
> + breakpoint_initialized = 1;
the content of breakpoint insn is unchanged. You can hard-code it in code.
> + }
> + *lenptr = sizeof (breakpoint);
> + return breakpoint;
> +}
> +
> +
> +/* ISSUE: Does this need an implementation?
> + NOTE: This function is called by "handle_inferior_event", when stepping
> + into a subroutine, but NOT a PLT stub (as that is handled
> specially). */
> +static CORE_ADDR
> +tilegx_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
> +{
> + return 0;
> +}
If this gdbarch hook is not implemented, generic_skip_trampoline_code
will be called, which returns 0 as well. You don't have to implement it.
> +
> +
> +/* For now, we'll just do a direct translation, but soon we may
> + * include an ASID and/or tilegx field in addresses, which doesn't
> + * appear in pointers -- so we need to keep the translation
> + * function around.
> + */
> +
> +static CORE_ADDR
> +tilegx_pointer_to_address (struct gdbarch *gdbarch,
> + struct type *type, const gdb_byte *buf)
> +{
> + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + return extract_unsigned_integer (buf, TYPE_LENGTH (type), byte_order);
> +}
Your implementation is exactly the same as its default function
`unsigned_pointer_to_address', so you don't have to implement it.
> +
> +static void
> +tilegx_address_to_pointer (struct gdbarch *gdbarch,
> + struct type *type, gdb_byte *buf, CORE_ADDR
> addr)
> +{
> + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> + store_unsigned_integer (buf, TYPE_LENGTH (type), byte_order, addr);
> +}
Likewise.
> +/* Function: tilegx_gdbarch_init
> + 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.
> + */
Incorrect comment style.
> +
> + /* 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_address_to_pointer (gdbarch, tilegx_address_to_pointer);
> + set_gdbarch_pointer_to_address (gdbarch, tilegx_pointer_to_address);
> +
> + 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);
^^ Indentation problem.
> +
> + /* 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_skip_trampoline_code (gdbarch, tilegx_skip_trampoline_code);
> +
> + 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);
^^^ newline in the wrong place.
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;
> +}
> +
> +static void
> +tilegx_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
> +{
> + /* We may not need anything here, but I think we need the function. */
Strctly speaking, this function should be renamed to
tilegx_linux_init_abi, and moved to tilegx-linux-tdep.c.
You have to call "linux_init_abi (info, gdbarch);" in this function.
> +}
> +
> +
> +/* Function: _initialize_tilegx_tdep
> + 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)
> +{
> + /* tile-sim is so slow it needs a longer timeout. */
> + remote_timeout = 60;
> +
> + register_gdbarch_init (bfd_arch_tilegx, tilegx_gdbarch_init);
> +
> + gdbarch_register_osabi (bfd_arch_tilegx, 0, GDB_OSABI_LINUX,
> tilegx_init_abi);
This should be called in _initialize_tilegx_linux_tdep defined in
tilegx-linux-tdep.c.
Last but no least, it is great if you can post the gdb testsuite result.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-20 15:18 ` Yao Qi
@ 2012-04-20 15:30 ` Jeff Kenton
2012-04-30 18:44 ` Pedro Alves
2012-04-23 15:05 ` Jeff Kenton
1 sibling, 1 reply; 13+ messages in thread
From: Jeff Kenton @ 2012-04-20 15:30 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
On 04/20/2012 11:09 AM, Yao Qi wrote:
> I don't know tile-gx process at all, but some comments on code style.
Thank you for the comments. I will make those changes.
> Last but not least, it is great if you can post the gdb testsuite
> result. -- Yao (é½å°§)
=== gdb Summary ===
# of expected passes 18181
# of unexpected failures 625
# of expected failures 100
# of known failures 59
# of untested testcases 12
# of unresolved testcases 4
# of unsupported tests 118
/gdb_tests/gdb/build/gdb/testsuite/../../gdb/gdb version
7.4.50.20120410 -nw -nx -data-directory
/gdb_tests/gdb/build/gdb/testsuite/../data-directory
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-20 15:30 ` Jeff Kenton
@ 2012-04-30 18:44 ` Pedro Alves
2012-04-30 19:06 ` Jeff Kenton
2012-05-07 14:37 ` Jeff Kenton
0 siblings, 2 replies; 13+ messages in thread
From: Pedro Alves @ 2012-04-30 18:44 UTC (permalink / raw)
To: Jeff Kenton; +Cc: Yao Qi, gdb-patches
I meant to reply to this before, but it slipped...
On 04/20/2012 04:23 PM, Jeff Kenton wrote:
> On 04/20/2012 11:09 AM, Yao Qi wrote:
>> I don't know tile-gx process at all, but some comments on code style.
>
> Thank you for the comments. I will make those changes.
>
>> Last but not least, it is great if you can post the gdb testsuite result. -- Yao (é½å°§)
>
> === gdb Summary ===
>
> # of expected passes 18181
> # of unexpected failures 625
Did you look at what is causing these hundreds of failures? Although there
are thousands of passes, such high failure rate is usually indicative of
something badly borked. You'd be surprised at how far in testsuite results
you can get with a gdb that manages to loads programs, but is a brick
at actually debugging live programs ...
> # of expected failures 100
> # of known failures 59
> # of untested testcases 12
> # of unresolved testcases 4
> # of unsupported tests 118
> /gdb_tests/gdb/build/gdb/testsuite/../../gdb/gdb version 7.4.50.20120410 -nw -nx -data-directory /gdb_tests/gdb/build/gdb/testsuite/../data-directory
--
Pedro Alves
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-30 18:44 ` Pedro Alves
@ 2012-04-30 19:06 ` Jeff Kenton
2012-04-30 19:17 ` Pedro Alves
2012-05-07 14:37 ` Jeff Kenton
1 sibling, 1 reply; 13+ messages in thread
From: Jeff Kenton @ 2012-04-30 19:06 UTC (permalink / raw)
To: Pedro Alves; +Cc: Yao Qi, gdb-patches
On 04/30/2012 02:43 PM, Pedro Alves wrote:
> I meant to reply to this before, but it slipped...
>
> On 04/20/2012 04:23 PM, Jeff Kenton wrote:
>
> === gdb Summary ===
>
> # of expected passes 18181
> # of unexpected failures 625
>
> Did you look at what is causing these hundreds of failures? Although there
> are thousands of passes, such high failure rate is usually indicative of
> something badly borked. You'd be surprised at how far in testsuite results
> you can get with a gdb that manages to loads programs, but is a brick
> at actually debugging live programs ...
>
>> # of expected failures 100
>> # of known failures 59
>> # of untested testcases 12
>> # of unresolved testcases 4
>> # of unsupported tests 118
>> /gdb_tests/gdb/build/gdb/testsuite/../../gdb/gdb version 7.4.50.20120410 -nw -nx -data-directory /gdb_tests/gdb/build/gdb/testsuite/../data-directory
>
We use it on production systems, so lots of things work. Checking the
failures is on my list of things to do. Is there a target failure
threshhold we need to hit before our GDB is accepted, or can we submit
what we have (with the fixes you specified) and work on the remaining
test suite failures afterwards?
--jeff kenton
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-30 19:06 ` Jeff Kenton
@ 2012-04-30 19:17 ` Pedro Alves
0 siblings, 0 replies; 13+ messages in thread
From: Pedro Alves @ 2012-04-30 19:17 UTC (permalink / raw)
To: Jeff Kenton; +Cc: Yao Qi, gdb-patches
On 04/30/2012 07:51 PM, Jeff Kenton wrote:
> On 04/30/2012 02:43 PM, Pedro Alves wrote:
>> I meant to reply to this before, but it slipped...
>>
>> On 04/20/2012 04:23 PM, Jeff Kenton wrote:
>>
>> === gdb Summary ===
>>
>> # of expected passes 18181
>> # of unexpected failures 625
>>
>> Did you look at what is causing these hundreds of failures? Although there
>> are thousands of passes, such high failure rate is usually indicative of
>> something badly borked. You'd be surprised at how far in testsuite results
>> you can get with a gdb that manages to loads programs, but is a brick
>> at actually debugging live programs ...
>>
>>> # of expected failures 100
>>> # of known failures 59
>>> # of untested testcases 12
>>> # of unresolved testcases 4
>>> # of unsupported tests 118
>>> /gdb_tests/gdb/build/gdb/testsuite/../../gdb/gdb version 7.4.50.20120410 -nw -nx -data-directory /gdb_tests/gdb/build/gdb/testsuite/../data-directory
>>
>
> We use it on production systems, so lots of things work. Checking the failures is on my list of things to do. Is there a target failure threshhold we need to hit before our GDB is accepted, or can we submit what we have (with the fixes you specified) and work on the remaining test suite failures afterwards?
There's no threshold, and certainly zero fails are not expected. Not even the
most maintained ports get that far, unfortunately. So we'll accept the port anyway.
But I'd be happier if at least you had browsed the gdb.sum/gdb.log for obvious
issues, and at least (any) internal-errors that show up are given some
consideration.
--
Pedro Alves
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-30 18:44 ` Pedro Alves
2012-04-30 19:06 ` Jeff Kenton
@ 2012-05-07 14:37 ` Jeff Kenton
2012-05-07 15:34 ` Yao Qi
1 sibling, 1 reply; 13+ messages in thread
From: Jeff Kenton @ 2012-05-07 14:37 UTC (permalink / raw)
To: Pedro Alves; +Cc: Yao Qi, gdb-patches
On 04/30/2012 02:43 PM, Pedro Alves wrote:
> I meant to reply to this before, but it slipped...
>
> On 04/20/2012 04:23 PM, Jeff Kenton wrote:
>>
>> === gdb Summary ===
>>
>> # of expected passes 18181
>> # of unexpected failures 625
>
> Did you look at what is causing these hundreds of failures? Although there
> are thousands of passes, such high failure rate is usually indicative of
> something badly borked. You'd be surprised at how far in testsuite results
> you can get with a gdb that manages to loads programs, but is a brick
> at actually debugging live programs ...
>
A small number of tests are causing 75% of them (FAIL counts and test
names shown):
12 FAIL: gdb.base/break-interp.exp:
13 FAIL: gdb.base/args.exp:
14 FAIL: gdb.threads/thread-find.exp:
15 FAIL: gdb.opt/inline-cmds.exp:
15 FAIL: gdb.threads/tls.exp:
16 FAIL: gdb.threads/watchpoint-fork.exp:
18 FAIL: gdb.trace/save-trace.exp:
24 FAIL: gdb.threads/linux-dp.exp:
100 FAIL: gdb.threads/attach-into-signal.exp:
112 FAIL: gdb.cp/meth-typedefs.exp:
114 FAIL: gdb.base/sigstep.exp:
--jeff kenton
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-20 15:18 ` Yao Qi
2012-04-20 15:30 ` Jeff Kenton
@ 2012-04-23 15:05 ` Jeff Kenton
2012-04-24 21:25 ` Joel Brobecker
2012-04-25 1:38 ` Yao Qi
1 sibling, 2 replies; 13+ messages in thread
From: Jeff Kenton @ 2012-04-23 15:05 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
On 04/20/2012 11:09 AM, Yao Qi wrote:
> I don't know tile-gx processor at all, but some comments on code style.
>> diff -r -u -N ./gdb-7.4.50.20120410/gdb/tilegx-linux-nat.c
>> ./gdb/tilegx-linux-nat.c
>> --- ./gdb-7.4.50.20120410/gdb/tilegx-linux-nat.c 1969-12-31
>> 19:00:00.000000000 -0500
>> +++ ./gdb/tilegx-linux-nat.c 2012-04-19 13:55:56.376489000 -0400
>> @@ -0,0 +1,188 @@
>> +
>> +void
>> +supply_gregset (struct regcache* regcache,
>> + const elf_gregset_t *gregsetp)
> Can be `static'? Function name "tilegx_supply_gregset" is better.
>
>
Yao,
I modeled this, and the other "regset" routines, on existing code (e.g.,
sparc64-, hppa-, alpha-, s390-, ppc-) that all implement
supply_gregset() and expose that name for use by processor independent
code. See procfs.c: procfs_fetch_registers() and core-regset.c:
fetch_core_registers() for uses. supply_gregset is declared in gregset.h.
Unless there is now a better way to do it I will leave this as it is.
Thank you.
--jeff
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-23 15:05 ` Jeff Kenton
@ 2012-04-24 21:25 ` Joel Brobecker
2012-04-24 21:41 ` Joel Brobecker
2012-04-25 1:38 ` Yao Qi
1 sibling, 1 reply; 13+ messages in thread
From: Joel Brobecker @ 2012-04-24 21:25 UTC (permalink / raw)
To: Jeff Kenton; +Cc: Yao Qi, gdb-patches
> I modeled this, and the other "regset" routines, on existing code
> (e.g., sparc64-, hppa-, alpha-, s390-, ppc-) that all implement
> supply_gregset() and expose that name for use by processor
> independent code. See procfs.c: procfs_fetch_registers() and
> core-regset.c: fetch_core_registers() for uses. supply_gregset is
> declared in gregset.h.
Yeah, IIRC, supply_gregset (and its counterpart fill_greset) is
expected to be implemented by the "native" part of GDB (the -nat.c
file). Without it, GDB would not compile.
I'm wondering if this is something we could put in the target ops?
--
Joel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-24 21:25 ` Joel Brobecker
@ 2012-04-24 21:41 ` Joel Brobecker
0 siblings, 0 replies; 13+ messages in thread
From: Joel Brobecker @ 2012-04-24 21:41 UTC (permalink / raw)
To: Jeff Kenton; +Cc: Yao Qi, gdb-patches
> Yeah, IIRC, supply_gregset (and its counterpart fill_greset) is
> expected to be implemented by the "native" part of GDB (the -nat.c
> file). Without it, GDB would not compile.
>
> I'm wondering if this is something we could put in the target ops?
Just to be clear: I am not asking you to redesign this part of GDB!
Just thinking out loud, for possible future enhancements...
--
Joel
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-23 15:05 ` Jeff Kenton
2012-04-24 21:25 ` Joel Brobecker
@ 2012-04-25 1:38 ` Yao Qi
1 sibling, 0 replies; 13+ messages in thread
From: Yao Qi @ 2012-04-25 1:38 UTC (permalink / raw)
To: Jeff Kenton; +Cc: gdb-patches
On 04/23/2012 10:50 PM, Jeff Kenton wrote:
> I modeled this, and the other "regset" routines, on existing code (e.g.,
> sparc64-, hppa-, alpha-, s390-, ppc-) that all implement
> supply_gregset() and expose that name for use by processor independent
> code. See procfs.c: procfs_fetch_registers() and core-regset.c:
> fetch_core_registers() for uses. supply_gregset is declared in gregset.h.
>
> Unless there is now a better way to do it I will leave this as it is.
You are correct. supply_gregset is defined in *-nat.c files.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb)
2012-04-19 20:18 [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb) Jeff Kenton
2012-04-20 15:18 ` Yao Qi
@ 2012-04-20 19:05 ` Tom Tromey
1 sibling, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2012-04-20 19:05 UTC (permalink / raw)
To: Jeff Kenton; +Cc: gdb-patches
>>>>> "Jeff" == Jeff Kenton <jkenton@tilera.com> writes:
Jeff> diff -r -u -N ./gdb-7.4.50.20120410/gdb/gdbserver/linux-tile-low.c
Jeff> ./gdb/gdbserver/linux-tile-low.c
Jeff> --- ./gdb-7.4.50.20120410/gdb/gdbserver/linux-tile-low.c
Jeff> 1969-12-31 19:00:00.000000000 -0500
Jeff> +++ ./gdb/gdbserver/linux-tile-low.c 2012-04-19 13:55:56.328492000 -0400
Jeff> @@ -0,0 +1,123 @@
Jeff> +#include "server.h"
Jeff> +#include "linux-low.h"
This file needs a copyright header.
Tom
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2012-05-07 15:34 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-19 20:18 [PATCH] Add support for Tilera TILE-Gx processor (part 2/2: gdb) Jeff Kenton
2012-04-20 15:18 ` Yao Qi
2012-04-20 15:30 ` Jeff Kenton
2012-04-30 18:44 ` Pedro Alves
2012-04-30 19:06 ` Jeff Kenton
2012-04-30 19:17 ` Pedro Alves
2012-05-07 14:37 ` Jeff Kenton
2012-05-07 15:34 ` Yao Qi
2012-04-23 15:05 ` Jeff Kenton
2012-04-24 21:25 ` Joel Brobecker
2012-04-24 21:41 ` Joel Brobecker
2012-04-25 1:38 ` Yao Qi
2012-04-20 19:05 ` Tom Tromey
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox