From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29964 invoked by alias); 8 Jul 2013 09:28:18 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 29933 invoked by uid 89); 8 Jul 2013 09:28:16 -0000 X-Spam-SWARE-Status: No, score=1.6 required=5.0 tests=AWL,BAYES_99,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,KAM_STOCKGEN,RCVD_IN_DNSWL_LOW,RCVD_IN_HOSTKARMA_YE,SPF_PASS,TW_AV,TW_CF,TW_CN,TW_CP,TW_DR,TW_EG,TW_HW,TW_QP,TW_RG,TW_SM,TW_TD,TW_YM autolearn=no version=3.3.1 Received: from mail-la0-f52.google.com (HELO mail-la0-f52.google.com) (209.85.215.52) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Mon, 08 Jul 2013 09:27:50 +0000 Received: by mail-la0-f52.google.com with SMTP id fo12so3597852lab.11 for ; Mon, 08 Jul 2013 02:27:46 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.112.189.101 with SMTP id gh5mr10236084lbc.73.1373275666435; Mon, 08 Jul 2013 02:27:46 -0700 (PDT) Received: by 10.112.71.139 with HTTP; Mon, 8 Jul 2013 02:27:46 -0700 (PDT) Date: Mon, 08 Jul 2013 09:28:00 -0000 Message-ID: Subject: [PATCH 1/5] Code for nds32 target From: Wei-cheng Wang To: gdb-patches@sourceware.org Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-SW-Source: 2013-07/txt/msg00224.txt.bz2 2013-07-08 Wei-Cheng Wang * Makefile.in (ALL_TARGET_OBS): Add nds32-tdep.o, nds32-linux-tdep.o, nds32-utils.o and nds32-remote.o. (ALLDEPFILES): Add nds32-tdep.c, nds32-linux-tdep.c, nds32-utils.c and nds32-remote.c. * configure.host: Add nds32*-linux* as host. * configure.tgt: Add nds32* and nds32*-linux* as target. * nds32-linux-nat.c: New file. * nds32-linux-tdep.c: New file. * nds32-linux-tdep.h: New file. * nds32-remote.c: New file. * nds32-remote.h: New file. * nds32-tdep.c: New file. * nds32-tdep.h: New file. * nds32-utils.c: New file. * nds32-utils.h: New file. * config/nds32/linux.mh: New file. * features/Makefile (WHICH): Add nds32-linux, nds32-freg0-linux, nds32-freg1-linux and nds32-freg2-linux. * features/nds32-linux.xml: New file. * features/nds32-core.xml: New file. * features/nds32-freg0.xml: New file. * features/nds32-freg1.xml: New file. * features/nds32-freg2.xml: New file. * features/nds32-freg3.xml: New file. * features/nds32-freg3-linux.xml: New file. * features/nds32-freg0-linux.xml: New file. * features/nds32-freg1-linux.xml: New file. * features/nds32-freg2-linux.xml: New file. * features/nds32-linux.c: New file (autogenerated). * features/nds32-freg0-linux.c: New file (autogenerated). * features/nds32-freg1-linux.c: New file (autogenerated). * features/nds32-freg2-linux.c: New file (autogenerated). * features/nds32-freg3-linux.c: New file (autogenerated). * regformats/nds32-linux.dat: New file (autogenerated). * regformats/nds32-freg0-linux.dat: New file (autogenerated). * regformats/nds32-freg1-linux.dat: New file (autogenerated). * regformats/nds32-freg2-linux.dat: New file (autogenerated). * regformats/nds32-freg3-linux.dat: New file (autogenerated). --- diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 4694adc..a116fea 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -574,6 +574,7 @@ ALL_TARGET_OBS =3D \ moxie-tdep.o \ msp430-tdep.o \ mt-tdep.o \ + nds32-tdep.o nds32-linux-tdep.o nds32-utils.o nds32-remote.o \ nios2-tdep.o nios2-linux-tdep.o \ nto-tdep.o \ ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o \ @@ -1519,6 +1520,7 @@ ALLDEPFILES =3D \ mipsnbsd-nat.c mipsnbsd-tdep.c \ mips64obsd-nat.c mips64obsd-tdep.c \ msp430-tdep.c \ + nds32-tdep.c nds32-linux-tdep.c nds32-utils.c nds32-remote.c \ nios2-tdep.c nios2-linux-tdep.c \ nbsd-nat.c nbsd-tdep.c obsd-tdep.c \ solib-osf.c \ diff --git a/gdb/config/nds32/linux.mh b/gdb/config/nds32/linux.mh new file mode 100644 index 0000000..eab0e57 --- /dev/null +++ b/gdb/config/nds32/linux.mh @@ -0,0 +1,10 @@ +# Host: nds32 based machine running GNU/Linux + +NAT_FILE=3D config/nm-linux.h +NATDEPFILES=3D inf-ptrace.o fork-child.o \ + nds32-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 +NAT_CDEPS =3D $(srcdir)/proc-service.list + +LOADLIBES=3D -ldl $(RDYNAMIC) diff --git a/gdb/configure.host b/gdb/configure.host index 85f4491..a4c4135 100644 --- a/gdb/configure.host +++ b/gdb/configure.host @@ -54,6 +54,7 @@ sh*) gdb_host_cpu=3Dsh ;; tilegx*) gdb_host_cpu=3Dtilegx ;; x86_64*) gdb_host_cpu=3Di386 ;; m32r*) gdb_host_cpu=3Dm32r ;; +nds32*) gdb_host_cpu=3Dnds32 ;; xtensa*) gdb_host_cpu=3Dxtensa ;; *) gdb_host_cpu=3D$host_cpu ;; @@ -126,6 +127,8 @@ mips*-*-netbsd* | mips*-*-knetbsd*-gnu) gdb_host=3Dnbsd ;; mips64*-*-openbsd*) gdb_host=3Dobsd64 ;; +nds32*-linux*) gdb_host=3Dlinux ;; + powerpc-*-aix* | rs6000-*-*) gdb_host=3Daix ;; powerpc*-*-freebsd*) gdb_host=3Dfbsd ;; diff --git a/gdb/configure.tgt b/gdb/configure.tgt index 260a0df..a65f483 100644 --- a/gdb/configure.tgt +++ b/gdb/configure.tgt @@ -401,6 +401,20 @@ mt-*-*) gdb_target_obs=3D"mt-tdep.o" ;; +nds32*-*-linux*) + # Target: GNU/Linux NDS32 + gdb_target_obs=3D"nds32-tdep.o nds32-linux-tdep.o nds32-utils.o nds32-rem= ote.o \ + glibc-tdep.o solib-svr4.o symfile-mem.o linux-tdep.o" + build_gdbserver=3Dyes + gdb_sim=3D../sim/nds32/libsim.a + ;; + +nds32*) + # Target: AndesTech nds32 core + gdb_target_obs=3D"nds32-tdep.o nds32-utils.o nds32-remote.o monitor.o dsr= ec.o" + gdb_sim=3D../sim/nds32/libsim.a + ;; + nios2*-*-linux*) # Target: Altera Nios II running Linux gdb_target_obs=3D"nios2-tdep.o nios2-linux-tdep.o solib-svr4.o \ diff --git a/gdb/features/Makefile b/gdb/features/Makefile index aee57d2..53f3bed 100644 --- a/gdb/features/Makefile +++ b/gdb/features/Makefile @@ -42,6 +42,8 @@ WHICH =3D aarch64 \ i386/x32-avx i386/x32-avx-linux \ mips-linux mips-dsp-linux \ mips64-linux mips64-dsp-linux \ + nds32-linux nds32-freg0-linux nds32-freg1-linux nds32-freg2-linux \ + nds32-freg3-linux \ nios2-linux \ rs6000/powerpc-32 \ rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \ @@ -74,6 +76,11 @@ mips-expedite =3D r29,pc mips-dsp-expedite =3D r29,pc mips64-expedite =3D r29,pc mips64-dsp-expedite =3D r29,pc +nds32-linux-expedite =3D fp,sp,pc +nds32-freg0-linux-expedite =3D fp,sp,pc +nds32-freg1-linux-expedite =3D fp,sp,pc +nds32-freg2-linux-expedite =3D fp,sp,pc +nds32-freg3-linux-expedite =3D fp,sp,pc nios2-linux-expedite =3D sp,pc powerpc-expedite =3D r1,pc rs6000/powerpc-cell32l-expedite =3D r1,pc,r0,orig_r3,r4 diff --git a/gdb/features/feature_to_c.sh b/gdb/features/feature_to_c.sh old mode 100644 new mode 100755 diff --git a/gdb/features/nds32-core.xml b/gdb/features/nds32-core.xml new file mode 100644 index 0000000..8de8059 --- /dev/null +++ b/gdb/features/nds32-core.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/nds32-freg0-linux.c b/gdb/features/nds32-freg0-li= nux.c new file mode 100644 index 0000000..ecea1ce --- /dev/null +++ b/gdb/features/nds32-freg0-linux.c @@ -0,0 +1,67 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: nds32-freg0-linux.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_nds32_freg0_linux; +static void +initialize_tdesc_nds32_freg0_linux (void) +{ + struct target_desc *result =3D allocate_target_description (); + struct tdesc_feature *feature; + + set_tdesc_architecture (result, bfd_scan_arch ("n1h")); + + set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux")); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 26, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int"); + tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int"); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu"); + tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single"); + + tdesc_nds32_freg0_linux =3D result; +} diff --git a/gdb/features/nds32-freg0-linux.xml b/gdb/features/nds32-freg0-linux.xml new file mode 100644 index 0000000..5af24d0 --- /dev/null +++ b/gdb/features/nds32-freg0-linux.xml @@ -0,0 +1,14 @@ + + + + + + nds32 + GNU/Linux + + + diff --git a/gdb/features/nds32-freg0.xml b/gdb/features/nds32-freg0.xml new file mode 100644 index 0000000..2287222 --- /dev/null +++ b/gdb/features/nds32-freg0.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/gdb/features/nds32-freg1-linux.c b/gdb/features/nds32-freg1-li= nux.c new file mode 100644 index 0000000..8023081 --- /dev/null +++ b/gdb/features/nds32-freg1-linux.c @@ -0,0 +1,71 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: nds32-freg1-linux.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_nds32_freg1_linux; +static void +initialize_tdesc_nds32_freg1_linux (void) +{ + struct target_desc *result =3D allocate_target_description (); + struct tdesc_feature *feature; + + set_tdesc_architecture (result, bfd_scan_arch ("n1h")); + + set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux")); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 26, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int"); + tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int"); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu"); + tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd4", 43, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd5", 44, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd6", 45, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd7", 46, 1, NULL, 64, "ieee_single"); + + tdesc_nds32_freg1_linux =3D result; +} diff --git a/gdb/features/nds32-freg1-linux.xml b/gdb/features/nds32-freg1-linux.xml new file mode 100644 index 0000000..656e3b9 --- /dev/null +++ b/gdb/features/nds32-freg1-linux.xml @@ -0,0 +1,14 @@ + + + + + + nds32 + GNU/Linux + + + diff --git a/gdb/features/nds32-freg1.xml b/gdb/features/nds32-freg1.xml new file mode 100644 index 0000000..1d0dfd2 --- /dev/null +++ b/gdb/features/nds32-freg1.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/gdb/features/nds32-freg2-linux.c b/gdb/features/nds32-freg2-li= nux.c new file mode 100644 index 0000000..9640710 --- /dev/null +++ b/gdb/features/nds32-freg2-linux.c @@ -0,0 +1,79 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: nds32-freg2-linux.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_nds32_freg2_linux; +static void +initialize_tdesc_nds32_freg2_linux (void) +{ + struct target_desc *result =3D allocate_target_description (); + struct tdesc_feature *feature; + + set_tdesc_architecture (result, bfd_scan_arch ("n1h")); + + set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux")); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 26, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int"); + tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int"); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu"); + tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd4", 43, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd5", 44, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd6", 45, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd7", 46, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd8", 47, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd9", 48, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd10", 49, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd11", 50, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd12", 51, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd13", 52, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd14", 53, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd15", 54, 1, NULL, 64, "ieee_single"); + + tdesc_nds32_freg2_linux =3D result; +} diff --git a/gdb/features/nds32-freg2-linux.xml b/gdb/features/nds32-freg2-linux.xml new file mode 100644 index 0000000..8fa0e0d --- /dev/null +++ b/gdb/features/nds32-freg2-linux.xml @@ -0,0 +1,14 @@ + + + + + + nds32 + GNU/Linux + + + diff --git a/gdb/features/nds32-freg2.xml b/gdb/features/nds32-freg2.xml new file mode 100644 index 0000000..6b4c1d3 --- /dev/null +++ b/gdb/features/nds32-freg2.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/nds32-freg3-linux.c b/gdb/features/nds32-freg3-li= nux.c new file mode 100644 index 0000000..f0dc18b --- /dev/null +++ b/gdb/features/nds32-freg3-linux.c @@ -0,0 +1,95 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: nds32-freg3-linux.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_nds32_freg3_linux; +static void +initialize_tdesc_nds32_freg3_linux (void) +{ + struct target_desc *result =3D allocate_target_description (); + struct tdesc_feature *feature; + + set_tdesc_architecture (result, bfd_scan_arch ("n1h")); + + set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux")); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 26, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int"); + tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int"); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.fpu"); + tdesc_create_reg (feature, "fd0", 39, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd1", 40, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd2", 41, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd3", 42, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd4", 43, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd5", 44, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd6", 45, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd7", 46, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd8", 47, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd9", 48, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd10", 49, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd11", 50, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd12", 51, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd13", 52, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd14", 53, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd15", 54, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd16", 55, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd17", 56, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd18", 57, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd19", 58, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd20", 59, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd21", 60, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd22", 61, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd23", 62, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd24", 63, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd25", 64, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd26", 65, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd27", 66, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd28", 67, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd29", 68, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd30", 69, 1, NULL, 64, "ieee_single"); + tdesc_create_reg (feature, "fd31", 70, 1, NULL, 64, "ieee_single"); + + tdesc_nds32_freg3_linux =3D result; +} diff --git a/gdb/features/nds32-freg3-linux.xml b/gdb/features/nds32-freg3-linux.xml new file mode 100644 index 0000000..b472420 --- /dev/null +++ b/gdb/features/nds32-freg3-linux.xml @@ -0,0 +1,14 @@ + + + + + + nds32 + GNU/Linux + + + diff --git a/gdb/features/nds32-freg3.xml b/gdb/features/nds32-freg3.xml new file mode 100644 index 0000000..766e570 --- /dev/null +++ b/gdb/features/nds32-freg3.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gdb/features/nds32-linux.c b/gdb/features/nds32-linux.c new file mode 100644 index 0000000..3dee14d --- /dev/null +++ b/gdb/features/nds32-linux.c @@ -0,0 +1,61 @@ +/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: + Original: nds32-linux.xml */ + +#include "defs.h" +#include "osabi.h" +#include "target-descriptions.h" + +struct target_desc *tdesc_nds32_linux; +static void +initialize_tdesc_nds32_linux (void) +{ + struct target_desc *result =3D allocate_target_description (); + struct tdesc_feature *feature; + + set_tdesc_architecture (result, bfd_scan_arch ("n1h")); + + set_tdesc_osabi (result, osabi_from_tdesc_string ("GNU/Linux")); + + feature =3D tdesc_create_feature (result, "org.gnu.gdb.nds32.core"); + tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r13", 13, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r14", 14, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r15", 15, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r16", 16, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r17", 17, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r18", 18, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r19", 19, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r20", 20, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r21", 21, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r22", 22, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r23", 23, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r24", 24, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "r25", 25, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 26, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "", 27, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "fp", 28, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "gp", 29, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "lp", 30, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "sp", 31, 1, NULL, 32, "data_ptr"); + tdesc_create_reg (feature, "pc", 32, 1, NULL, 32, "code_ptr"); + tdesc_create_reg (feature, "d0lo", 33, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d0hi", 34, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1lo", 35, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "d1hi", 36, 1, NULL, 32, "int"); + tdesc_create_reg (feature, "orig_r0", 37, 1, "system", 32, "int"); + tdesc_create_reg (feature, "fucpr", 38, 1, "system", 32, "int"); + + tdesc_nds32_linux =3D result; +} diff --git a/gdb/features/nds32-linux.xml b/gdb/features/nds32-linux.xml new file mode 100644 index 0000000..74e41ce --- /dev/null +++ b/gdb/features/nds32-linux.xml @@ -0,0 +1,13 @@ + + + + + + nds32 + GNU/Linux + + diff --git a/gdb/nds32-linux-nat.c b/gdb/nds32-linux-nat.c new file mode 100644 index 0000000..2f87822 --- /dev/null +++ b/gdb/nds32-linux-nat.c @@ -0,0 +1,299 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#include "defs.h" +#include "inferior.h" +#include "gdbcore.h" +#include "gdb_string.h" +#include "regcache.h" +#include "target.h" +#include "linux-nat.h" +#include "target-descriptions.h" +#include "auxv.h" + +#include +#include +#include +#include +#include + +/* Prototypes for supply_gregset etc. */ +#include "gregset.h" + +/* Defines ps_err_e, struct ps_prochandle. */ +#include "gdb_proc_service.h" + +#include "nds32-tdep.h" +#include "nds32-linux-tdep.h" +#include "features/nds32-linux.c" + +void _initialize_nds32_linux_nat (void); + +#define GET_THREAD_ID(PTID) get_thread_id (PTID) + +/* On GNU/Linux, threads are implemented as pseudo-processes, in which + case we may be tracing more than one process at a time. In that + case, inferior_ptid will contain the main process ID and the + individual thread (process) ID. get_thread_id () is used to get + the thread id if it's available, and the process id otherwise. */ + +int +get_thread_id (ptid_t ptid) +{ + int tid =3D TIDGET (ptid); + + if (0 =3D=3D tid) + tid =3D PIDGET (ptid); + return tid; +} + +/* Fetch a general register of the process and store into register + cache REGCACHE. See: arch/nds32/include/asm/ptrace.h */ + +static void +fetch_register (struct regcache *regcache, int regno) +{ + int ret, tid; + elf_gregset_t regs; + + /* Check whether the size of gregset is consistent with kernel. */ + gdb_assert (sizeof (elf_gregset_t) >=3D (sizeof (long) * 50)); + + /* Get the thread id for the ptrace call. */ + tid =3D GET_THREAD_ID (inferior_ptid); + + ret =3D ptrace (PTRACE_GETREGS, tid, 0, ®s); + if (ret < 0) + { + warning (_("Unable to fetch general register.")); + return; + } + + if (regno >=3D NDS32_R0_REGNUM && regno < NDS32_LINUX_NUM_GPRS + && nds32_ptreg_map[regno] !=3D -1) + regcache_raw_supply (regcache, regno, + (char *) ®s[nds32_ptreg_map[regno]]); +} + +/* Fetch all general registers of the process and store into register + cache REGCACHE. */ + +static void +fetch_regs (struct regcache *regcache) +{ + int ret, regno, tid; + elf_gregset_t regs; + + /* Get the thread id for the ptrace call. */ + tid =3D GET_THREAD_ID (inferior_ptid); + + ret =3D ptrace (PTRACE_GETREGS, tid, 0, ®s); + if (ret < 0) + { + warning (_("Unable to fetch general registers.")); + return; + } + + for (regno =3D NDS32_R0_REGNUM; regno < NDS32_LINUX_NUM_GPRS; regno++) + { + if (nds32_ptreg_map[regno] =3D=3D -1) + continue; + regcache_raw_supply (regcache, regno, + (char *) ®s[nds32_ptreg_map[regno]]); + } +} + +/* Store all general registers of the process from the values in + register cache REGCACHE. */ + +static void +store_register (const struct regcache *regcache, int regno) +{ + int ret, tid; + elf_gregset_t regs; + + if (REG_VALID !=3D regcache_register_status (regcache, regno)) + return; + + /* Get the thread id for the ptrace call. */ + tid =3D GET_THREAD_ID (inferior_ptid); + + /* Get the general registers from the process. */ + ret =3D ptrace (PTRACE_GETREGS, tid, 0, ®s); + if (ret < 0) + { + warning (_("Unable to fetch general registers.")); + return; + } + + if (regno >=3D NDS32_R0_REGNUM && regno < NDS32_LINUX_NUM_GPRS + && nds32_ptreg_map[regno] !=3D -1) + regcache_raw_collect (regcache, regno, + (char *) ®s[nds32_ptreg_map[regno]]); + + ret =3D ptrace (PTRACE_SETREGS, tid, 0, ®s); + if (ret < 0) + { + warning (_("Unable to store general register.")); + return; + } +} + +static void +store_regs (const struct regcache *regcache) +{ + int ret, regno, tid; + elf_gregset_t regs; + + /* Get the thread id for the ptrace call. */ + tid =3D GET_THREAD_ID (inferior_ptid); + + /* Fetch the general registers. */ + ret =3D ptrace (PTRACE_GETREGS, tid, 0, ®s); + if (ret < 0) + { + warning (_("Unable to fetch general registers.")); + return; + } + + for (regno =3D 0; regno < NDS32_LINUX_NUM_GPRS; regno++) + { + if (nds32_ptreg_map[regno] =3D=3D -1) + continue; + if (REG_VALID !=3D regcache_register_status (regcache, regno)) + regcache_raw_collect (regcache, regno, + (char *) ®s[nds32_ptreg_map[regno]]); + } + + ret =3D ptrace (PTRACE_SETREGS, tid, 0, ®s); + + if (ret < 0) + { + warning (_("Unable to store general registers.")); + return; + } +} + +/* Fetch registers from the child process. Fetch all registers if + REGNO =3D=3D -1, otherwise fetch all general registers or all floating + point registers depending upon the value of REGNO. */ + +static void +nds32_linux_fetch_inferior_registers (struct target_ops *ops, + struct regcache *regcache, + int regno) +{ + /* TODO: Handle AUDIO and FPU registers. */ + + if (-1 =3D=3D regno) + fetch_regs (regcache); + else + fetch_register (regcache, regno); +} + +/* Store registers back into the inferior. Store all registers if + REGNO =3D=3D -1, otherwise store all general registers or all floating + point registers depending upon the value of REGNO. */ + +static void +nds32_linux_store_inferior_registers (struct target_ops *ops, + struct regcache *regcache, + int regno) +{ + /* TODO: Handle AUDIO and FPU registers. */ + + if (-1 =3D=3D regno) + store_regs (regcache); + else + store_register (regcache, regno); +} + +/* Wrapper functions for the standard regset handling, used by + thread debugging. */ + +void +fill_gregset (const struct regcache *regcache, + gdb_gregset_t *gregsetp, int regno) +{ + nds32_linux_collect_gregset (NULL, regcache, regno, gregsetp, 0); +} + +void +supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp) +{ + nds32_linux_supply_gregset (NULL, regcache, -1, gregsetp, 0); +} + +void +fill_fpregset (const struct regcache *regcache, + gdb_fpregset_t *fpregsetp, int regno) +{ + warning (_("fill_fpregset not implemented")); +} + +/* Fill GDB's register array with the floating-point register values + in *fpregsetp. */ + +void +supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregset= p) +{ + warning (_("supply_fpregset not implemented")); +} + +/* Fetch the thread-local storage pointer for libthread_db. */ + +#if 0 +/* TODO: TLS is not supported, yet. */ + +ps_err_e +ps_get_thread_area (const struct ps_prochandle *ph, + lwpid_t lwpid, int idx, void **base) +{ +} +#endif + +static const struct target_desc * +nds32_linux_read_description (struct target_ops *ops) +{ + CORE_ADDR nds32_hwcap =3D 0; + + /* TODO: FPU registers. */ + + return tdesc_nds32_linux; +} + +void +_initialize_nds32_linux_nat (void) +{ + struct target_ops *t; + + /* Fill in the generic GNU/Linux methods. */ + t =3D linux_target (); + + /* Add our register access methods. */ + t->to_fetch_registers =3D nds32_linux_fetch_inferior_registers; + t->to_store_registers =3D nds32_linux_store_inferior_registers; + + t->to_read_description =3D nds32_linux_read_description; + + /* Register the target. */ + linux_nat_add_target (t); + initialize_tdesc_nds32_linux (); +} diff --git a/gdb/nds32-linux-tdep.c b/gdb/nds32-linux-tdep.c new file mode 100644 index 0000000..79d51cd --- /dev/null +++ b/gdb/nds32-linux-tdep.c @@ -0,0 +1,320 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#include "defs.h" +#include "gdbcore.h" +#include "frame.h" +#include "value.h" +#include "regcache.h" +#include "inferior.h" +#include "osabi.h" +#include "reggroups.h" +#include "regset.h" +#include "target-descriptions.h" + +#include "gdb_string.h" + +#include "glibc-tdep.h" +#include "solib-svr4.h" + +#include "trad-frame.h" +#include "frame-unwind.h" + +#include "nds32-tdep.h" +#include "nds32-linux-tdep.h" + +extern struct nds32_gdb_config nds32_config; + +void _initialize_nds32_linux_tdep (void); + +/* Recognizing signal handler frames. */ + +/* GNU/Linux has two flavors of signals. Normal signal handlers, and + "realtime" (RT) signals. The RT signals can provide additional + information to the signal handler if the SA_SIGINFO flag is set + when establishing a signal handler using `sigaction'. It is not + unlikely that future versions of GNU/Linux will support SA_SIGINFO + for normal signals too. */ + +/* When the NDS32 Linux kernel calls a signal handler and the + SA_RESTORER flag isn't set, the return address points to a bit of + code on the stack. This function returns whether the PC appears to + be within this bit of code. + + The instructions for normal and realtime signals are + syscall #__NR_sigreturn ( 0x26 0x01 0xDC 0x0B) + or + syscall #__NR_rt_sigreturn ( 0x26 0x02 0xB4 0x0B) + + Checking for the code sequence should be somewhat reliable, because + the effect is to call the system call sigreturn. This is unlikely + to occur anywhere other than in a signal trampoline. + + It kind of sucks that we have to read memory from the process in + order to identify a signal trampoline, but there doesn't seem to be + any other way. Therefore we only do the memory reads if no + function name could be identified, which should be the case since + the code is on the stack. + + Detection of signal trampolines for handlers that set the + SA_RESTORER flag is in general not possible. Unfortunately this is + what the GNU C Library has been doing for quite some time now. + However, as of version 2.1.2, the GNU C Library uses signal + trampolines (named __restore and __restore_rt) that are identical + to the ones used by the kernel. Therefore, these trampolines are + supported too. */ + +/* syscall #0x5077 */ +static const unsigned char NDS32_SIGRETURN_INSN[] =3D +{ + 0x64, 0x0a, 0x0e, 0xeb +}; + +/* syscall #0x50ad */ +static const unsigned char NDS32_RT_SIGRETURN_INSN[] =3D +{ + 0x64, 0x0a, 0x15, 0xab +}; + +int nds32_linux_sc_reg_offset[] =3D +{ + /* r0 - r9 */ + 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, + /* r10 - r19 */ + 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, + /* r20 - r25, 26, 27 */ + 92, 96, 100, 104, 108, 112, -1, -1, + /* fp, gp, lr, sp */ + 116, 120, 124, 128, + /* pc, d0lo, d0hi, d1lo, d1hi */ + 148, 140, 144, 132, 136 +}; + +struct nds32_frame_cache +{ + CORE_ADDR base, pc; + struct trad_frame_saved_reg *saved_regs; +}; + +/* Find start of signal frame. */ + +static CORE_ADDR +nds32_linux_sigtramp_start (struct frame_info *this_frame) +{ + const int SIGLEN =3D sizeof (NDS32_SIGRETURN_INSN); + CORE_ADDR pc =3D get_frame_pc (this_frame); + gdb_byte buf[SIGLEN]; + + if (!safe_frame_unwind_memory (this_frame, pc, buf, SIGLEN)) + return 0; + + if (memcmp (buf, NDS32_SIGRETURN_INSN, SIGLEN) !=3D 0) + return 0; + + return pc; +} + +/* Find start of rt_signal frame. */ + +static CORE_ADDR +nds32_linux_rt_sigtramp_start (struct frame_info *this_frame) +{ + const int SIGLEN =3D sizeof (NDS32_RT_SIGRETURN_INSN); + CORE_ADDR pc =3D get_frame_pc (this_frame); + gdb_byte buf[SIGLEN]; + + if (!safe_frame_unwind_memory (this_frame, pc, buf, SIGLEN)) + return 0; + + if (memcmp (buf, NDS32_RT_SIGRETURN_INSN, SIGLEN) !=3D 0) + return 0; + + return pc; +} + +/* Return whether the frame preceding NEXT_FRAME corresponds to a + GNU/Linux sigtramp routine. */ + +static int +nds32_linux_sigtramp_p (struct frame_info *this_frame) +{ + CORE_ADDR pc =3D get_frame_pc (this_frame); + const char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + + /* If we have NAME, we can optimize the search. The trampolines are + named __restore and __restore_rt. However, they aren't dynamically + exported from the shared C library, so the trampoline may appear to + be part of the preceding function. This should always be sigaction, + __sigaction, or __libc_sigaction (all aliases to the same function). = */ + if (name =3D=3D NULL) + return (nds32_linux_sigtramp_start (this_frame) !=3D 0 + || nds32_linux_rt_sigtramp_start (this_frame) !=3D 0); + + return (strcmp ("__default_sa_restorer", name) =3D=3D 0 + || strcmp ("__default_rt_sa_restorer", name) =3D=3D 0); +} + +/* Offset to struct sigcontext in ucontext, from . */ +#define NDS32_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 0x18 + +/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp + routine, return the address of the associated sigcontext structure. */ + +static CORE_ADDR +nds32_linux_sigcontext_addr (struct frame_info *this_frame) +{ + CORE_ADDR pc; + CORE_ADDR sp; + gdb_byte buf[4]; + + sp =3D get_frame_sp (this_frame); + + /* sigcontext is at sp for sigtramp */ + pc =3D nds32_linux_sigtramp_start (this_frame); + if (pc) + return sp; + + pc =3D nds32_linux_rt_sigtramp_start (this_frame); + if (pc) + { + CORE_ADDR ucontext_addr; + int r2; + + /* Cole, Dec. 31th, 2010 + sigcontext is stored in frame->uc.uc_mcontext, Therefore, + there are two ways to get sigcontext. + The first way, direct access it in the stack.In this way, + we needs more knowledge of rt_sigtramp + The second way, &us is passed as parameter 3 of handler, + that would be R2 in NDS32 ABI.As long as we use generic + ucontext struct, I think it's easier to get sigcontext. */ + + r2 =3D get_frame_register_unsigned (this_frame, NDS32_R0_REGNUM + 2); + sp =3D r2; + /* This value is dependent on kernel. */ + sp +=3D NDS32_LINUX_UCONTEXT_SIGCONTEXT_OFFSET; + return sp; + } + + error (_("Couldn't recognize signal trampoline.")); + return 0; +} + +/* Supply GPR regset. + + Fill GDB register array with the general-purpose register values + in *GREGSETP. */ + +void +nds32_linux_supply_gregset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *gregs, size_t size) +{ + int i; + const char *regp =3D gregs; + + /* pseudo_shift =3D size =3D=3D 200 ? 24 : 0; */ + for (i =3D NDS32_R0_REGNUM; i < NDS32_LINUX_NUM_GPRS; i++) + { + /* FIXME: Review me after , , and SR regs + spec clear. [Harry@Mar.14.2006] */ + if (nds32_ptreg_map[i] =3D=3D -1) + continue; + + regcache_raw_supply (regcache, i, regp + nds32_ptreg_map[i] * 4); + } +} + +/* Collect GPR regset. */ + +void +nds32_linux_collect_gregset (const struct regset *regset, + const struct regcache *regcache, + int regnum, void *gregs_buf, size_t len) +{ + gdb_byte *regp =3D gregs_buf; + int regno; + + for (regno =3D NDS32_R0_REGNUM; regno < NDS32_LINUX_NUM_GPRS; regno++) + { + if (nds32_ptreg_map[regno] =3D=3D -1) + continue; + + if (regnum =3D=3D -1 || regnum =3D=3D regno) + regcache_raw_collect (regcache, regno, + regp + nds32_ptreg_map[regno] * 4); + } +} + +/* Implement gdbarch_regset_from_core_section method. */ + +static const struct regset * +nds32_linux_regset_from_core_section (struct gdbarch *core_arch, + const char *sect_name, size_t sect_size) +{ + struct gdbarch_tdep *tdep =3D gdbarch_tdep (core_arch); + + if (strcmp (sect_name, ".reg") =3D=3D 0) + return regset_alloc (core_arch, nds32_linux_supply_gregset, + nds32_linux_collect_gregset); + + /* TODO: fpreg ".reg2" */ + return NULL; +} + +static void +nds32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + const struct target_desc *tdesc =3D info.target_desc; + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + struct tdesc_arch_data *tdesc_data =3D (void *) info.tdep_info; + const struct tdesc_feature *feature; + + tdep->sigtramp_p =3D nds32_linux_sigtramp_p; + tdep->sigcontext_addr =3D nds32_linux_sigcontext_addr; + tdep->sc_pc_offset =3D 37 * 4; /* sc.fault_address */ + tdep->sc_sp_offset =3D 32 * 4; /* sc.sp */ + tdep->sc_lp_offset =3D 31 * 4; /* sc.lp */ + tdep->sc_fp_offset =3D 29 * 4; /* sc.fp */ + + tdep->sc_reg_offset =3D nds32_linux_sc_reg_offset; + tdep->sc_num_regs =3D ARRAY_SIZE (nds32_linux_sc_reg_offset); + + /* GNU/Linux uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets (gdbarch, + svr4_ilp32_fetch_link_map_offsets); + + /* Core file support. */ + /* FIXME: Cole, Dec 31th, 2010 + It seems this doesn't work? */ + set_gdbarch_regset_from_core_section (gdbarch, + nds32_linux_regset_from_core_section); + + set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); +} + +void +_initialize_nds32_linux_tdep (void) +{ + gdbarch_register_osabi (bfd_arch_nds32, 0, GDB_OSABI_LINUX, + nds32_linux_init_abi); +} diff --git a/gdb/nds32-linux-tdep.h b/gdb/nds32-linux-tdep.h new file mode 100644 index 0000000..40684fe --- /dev/null +++ b/gdb/nds32-linux-tdep.h @@ -0,0 +1,77 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#ifndef NDS32_LINUX_TDEP_H +#define NDS32_LINUX_TDEP_H + +extern struct target_desc *tdesc_nds32_linux; + +void nds32_linux_supply_gregset (const struct regset *regset, + struct regcache *regcache, int regnum, + const void *gregs, size_t size); +void nds32_linux_collect_gregset (const struct regset *regset, + const struct regcache *regcache, int regnum, + void *gregs_buf, size_t len); + +/* Mapping between the general-purpose registers in `struct user' + format and GDB's register array layout. + + FIXME: fix me after , , + and SR regs spec clear. [Harry@Mar.14.2006] + + Current remap layout depend on Tom's implementation in kernel header, + in ptrace.h and IR spec 0.1 (Jan.20.2006 version) + [Harry@Mar.16.2006] + + Note: -1 means unable to get from ptrace syscall + + Renumber according to arch/nds32/include/asm/ptrace.h + Not sure whether NDS32_r0 or NDS32_ORIG_r0 represents real $r0. + (current use NDS32_ORIG_r0) + Registers not mapped: NDS32_FUCOP_CTL, NDS32_osp. (42 & 43) + [Rudolph@Aug.18.2010] */ + +/* Map gdb regnum to pt_regs index. */ +static int nds32_ptreg_map[] =3D +{ + /* nds32-core */ + + /* r0 - r25 */ + 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, + /* r26 and r27 are reserved for kernel */ + -1, -1, + /* fp, gp, lp, sp */ + 39, 40, 41, 3, + /* pc */ + 2, + /* d0lo, d0hi, d1lo, d1hi */ + 10, 9, 12, 11, + + /* nds32-linux */ + + /* orig_r0, fucop */ + 4, 42 +}; + +#define NDS32_LINUX_NUM_GPRS (ARRAY_SIZE(nds32_ptreg_map)) + +#endif diff --git a/gdb/nds32-remote.c b/gdb/nds32-remote.c new file mode 100644 index 0000000..c088f0d --- /dev/null +++ b/gdb/nds32-remote.c @@ -0,0 +1,778 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#include "defs.h" +#include "gdb_string.h" +#include "gdbcore.h" +#include "gdbcmd.h" +#include "gdbtypes.h" +#include "cli/cli-decode.h" +#include "remote.h" +#include "regcache.h" +#include "user-regs.h" +#include "inferior.h" /* get_inferior_args () */ +#include "top.h" /* set_prompt () */ +#include "ui-out.h" /* current_uiout */ +#include "exceptions.h" /* TRY_CATCH */ +#include + +#include "nds32-remote.h" +#include "nds32-tdep.h" + +char *nds32_qparts [] =3D +{ + "qPart:nds32:ask:de", + "qPart:nds32:ask:mach", + "qPart:nds32:ask:base16", + "qPart:nds32:ask:pex1", + "qPart:nds32:ask:pex2", + "qPart:nds32:ask:div", + "qPart:nds32:ask:abi", + "qPart:nds32:ask:mfusr_pc", + "qPart:nds32:ask:fpu", + "qPart:nds32:ask:audio", + "qPart:nds32:ask:string", + "qPart:nds32:ask:reduced_regs", + "qPart:nds32:ask:video", + "qPart:nds32:ask:ifc", + "qPart:nds32:ask:elf_ver", + "qPart:nds32:ask:l2c", + "qPart:nds32:ask:mac", + "qPart:nds32:ask:cpu", /* core0, cpu, etc */ + "qPart:nds32:ask:target", /* SID, ICE */ + + "qPart:nds32:request:InvalidateCache", + "qPart:nds32:request:MemAccBus", + "qPart:nds32:request:MemAccCPU" +}; + +enum nds32_qparts_enum +{ + NDS32_Q_ENDIAN, + NDS32_Q_MACH, + NDS32_Q_BASE16, + NDS32_Q_PEX1, + NDS32_Q_PEX2, + NDS32_Q_DIV, + NDS32_Q_ABI, + NDS32_Q_MFUSR_PC, + NDS32_Q_FPU, + NDS32_Q_AUDIO, + NDS32_Q_STRING, + NDS32_Q_REDUCED_REGS, + NDS32_Q_VIDEO, + NDS32_Q_IFC, + NDS32_Q_ELF_VER, + NDS32_Q_L2C, + NDS32_Q_MAC, + NDS32_Q_CPU, + NDS32_Q_TARGET, + + NDS32_Q_INVALIDATE_CACHE, + NDS32_Q_ACC_BUS, + NDS32_Q_ACC_CPU, + NDS32_Q_END +}; + +enum nds32_remote_type +{ + nds32_rt_unknown =3D 0, + nds32_rt_sid, + nds32_rt_ice, + nds32_rt_ocd, +}; + +struct +{ + /* Target type of remote, SID, ICE or OpenOCD. */ + enum nds32_remote_type type; + /* CPU/CORE name read from remote. */ + char cpu[16]; + /* Default endian of remote. */ + enum bfd_endian endian; +} nds32_remote_info; + +void +nds32_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, + int *kindptr) +{ + if ((*pcptr) & 1) + error (_("bad address %p for inserting breakpoint"), (void *) *pcptr); + + /* ICEman/AICE have trouble on reading memory when the pcptr is P/A, + but CPU is in V/A mode. This code prevent GDB from reading memory. + ICEman will read memory itself if needed. + + See: Bug 7430 - GDB can't set a hardware break point with PA + if IT/DT is on. */ + + *kindptr =3D 2; +} + +/* Wrapper for execute a GDB CLI command. */ + +static void +nds32_execute_command (char *cmd, char *arg, int from_tty) +{ + int len; + char *line; + + if (arg =3D=3D NULL) + arg =3D ""; + len =3D strlen (arg) + strlen (cmd) + 2; + if (len > 1024) + error (_("Command line too long.")); + + line =3D alloca (len); + memset (line, 0, len); + if (arg !=3D NULL) + snprintf (line, len, "%s %s", cmd, arg); + else + snprintf (line, len, "%s", cmd); + execute_command (line, from_tty); +} + +static void +nds32_restore_remote_timeout (void *p) +{ + int value =3D *(int *) p; + + remote_timeout =3D value; +} + +/* Reset-target. + Set remote_timeout to 1000 sec to avoid timeout. */ + +static void +nds32_reset_target_command (char *args, int from_tty) +{ + int saved_remote_timeout =3D remote_timeout; + struct cleanup *back_to; + + back_to =3D make_cleanup (nds32_restore_remote_timeout, &saved_remote_ti= meout); + remote_timeout =3D 1000; + nds32_execute_command ("monitor reset target", NULL, from_tty); + registers_changed (); + do_cleanups (back_to); +} + +/* Callback for "nds32 reset-hold" command. */ + +static void +nds32_reset_hold_command (char *args, int from_tty) +{ + int saved_remote_timeout =3D remote_timeout; + struct cleanup *back_to; + + back_to =3D + make_cleanup (nds32_restore_remote_timeout, &saved_remote_timeout); + remote_timeout =3D 1000; + nds32_execute_command ("monitor reset hold", NULL, from_tty); + registers_changed (); + do_cleanups (back_to); +} + +/* Callback for "nds32 pipeline on" command. */ + +static void +nds32_pipeline_on_command (char *args, int from_tty) +{ + char cmd[256]; + + snprintf (cmd, sizeof (cmd), "monitor set %s pipeline-on 1", + args =3D=3D NULL ? "cpu" : args); + nds32_execute_command (cmd, NULL, from_tty); +} + +/* Callback for "nds32 pipeline off" command. */ + +static void +nds32_pipeline_off_command (char *args, int from_tty) +{ + char cmd[256]; + + snprintf (cmd, sizeof (cmd), "monitor set %s pipeline-on 0", + args =3D=3D NULL ? "cpu" : args); + nds32_execute_command (cmd, NULL, from_tty); +} + +/* Callback for "nds32 pipeline" command. */ + +static void +nds32_pipeline_command (char *args, int from_tty) +{ + error (_("Usage: nds32 pipeline (on|off) [cpu]")); +} + +/* Callback for "nds32 query" command. */ + +static void +nds32_query_command (char *args, int from_tty) +{ + error (_("Usage: nds32 query (profiling|perf-meter) [cpu] [human|ide]")); +} + +/* Callback for "nds32 reset" command. */ + +static void +nds32_reset_command (char *args, int from_tty) +{ + error (_("Usage: nds32 reset (profiling|perf-meter) [cpu]")); +} + +/* Pretty-print for profiling data. */ + +static void +nds32_print_human_table (int col, int row, const char *scsv) +{ + int i; + struct cleanup *table_cleanup =3D NULL; + struct cleanup *row_cleanup =3D NULL; + char *buf =3D NULL; + char **col_fldname; + char **col_hdrtext; + int *col_width; + enum ui_align *col_align; + struct bound_minimal_symbol msymbol; + CORE_ADDR addr; + char symbol_text[256]; + + buf =3D xstrdup (scsv); + make_cleanup (xfree, buf); + + /* Allocate header structures. */ + col_fldname =3D (char **) xmalloc (sizeof (col_fldname[0]) * col); + col_hdrtext =3D (char **) xmalloc (sizeof (col_hdrtext[0]) * col); + col_width =3D (int *) xmalloc (sizeof (col_width[0]) * col); + col_align =3D (enum ui_align *) xmalloc (sizeof (col_align[0]) * col); + + make_cleanup (xfree, col_fldname); + make_cleanup (xfree, col_hdrtext); + make_cleanup (xfree, col_width); + make_cleanup (xfree, col_align); + + /* Parsing column header. */ + i =3D 0; + while (*buf !=3D '\0' && i < col) + { + CORE_ADDR addr =3D 0; + char *sc =3D strchr (buf, ';'); + + *sc =3D '\0'; + col_fldname[i] =3D buf; + col_hdrtext[i] =3D col_fldname[i]; + if (col_fldname[i][0] =3D=3D '%') + col_width[i] =3D 6; + else + col_width[i] =3D strlen (col_hdrtext[i]) + 1; + + col_align[i] =3D ui_right; + + i++; + buf =3D sc + 1; + } + + gdb_assert (col =3D=3D i); + + /* Output table. */ + table_cleanup =3D make_cleanup_ui_out_table_begin_end + (current_uiout, col, row - 1, "ProfilingTable"); + for (i =3D 0; i < col; i++) + ui_out_table_header (current_uiout, col_width[i], col_align[i], + col_fldname[i], col_hdrtext[i]); + + ui_out_table_body (current_uiout); + + /* Parse buf into col/row. */ + i =3D 0; + row_cleanup =3D make_cleanup_ui_out_tuple_begin_end (current_uiout, "row= "); + while (*buf !=3D '\0') + { + char *sc =3D strchr (buf, ';'); + int offset; + + *sc =3D '\0'; + switch (i) + { + case 0: + ui_out_field_string (current_uiout, col_fldname[i], buf); + + /* Assume first column is address. */ + strcpy (symbol_text, "\n"); + addr =3D strtol (buf, NULL, 16); + msymbol =3D lookup_minimal_symbol_by_pc (addr); + if (!msymbol.minsym) + break; + + offset =3D addr - SYMBOL_VALUE_ADDRESS (msymbol.minsym); + if (offset) + snprintf (symbol_text, sizeof (symbol_text), "%s + 0x%x\n", + SYMBOL_PRINT_NAME (msymbol.minsym), offset); + else + snprintf (symbol_text, sizeof (symbol_text), "%s\n", + SYMBOL_PRINT_NAME (msymbol.minsym)); + break; + case 1: case 2: case 3: case 4: case 5: case 6: + ui_out_field_string (current_uiout, col_fldname[i], buf); + break; + } + + i++; + buf =3D sc + 1; + if (i =3D=3D col) + { + ui_out_text (current_uiout, symbol_text); + do_cleanups (row_cleanup); + i =3D 0; + row_cleanup =3D make_cleanup_ui_out_tuple_begin_end + (current_uiout, "row"); + } + } + + do_cleanups (table_cleanup); +} + +/* Callback for "nds32 query profiling" command. */ + +static void +nds32_query_profiling_command (char *args, int from_tty) +{ + /* For profiling, there will be multiple responses. */ + int row, col; + struct ui_file *res; + int i; + long int pkt_size; + char *pkt_buf =3D NULL; + struct ui_file_buffer ui_buf; + char *arg_cpu =3D "cpu"; + int arg_human =3D TRUE; + struct cleanup *back_to =3D NULL; + char **argv =3D NULL; + char *p; + + /* Initial size. It may be resized by getpkt. */ + pkt_size =3D 1024; + + res =3D mem_fileopen (); + back_to =3D make_cleanup_ui_file_delete (res); + + ui_buf.buf_size =3D 2048; + ui_buf.buf =3D xmalloc (ui_buf.buf_size); + pkt_buf =3D xmalloc (pkt_size); + + make_cleanup (free_current_contents, &ui_buf.buf); + make_cleanup (free_current_contents, &pkt_buf); + make_cleanup_restore_ui_file (&gdb_stdtarg); + + gdb_stdtarg =3D res; + + if (args !=3D NULL) + { + /* Parse arguments. */ + argv =3D gdb_buildargv (args); + make_cleanup_freeargv (argv); + } + + for (i =3D 0; argv && argv[i]; i++) + { + switch (i) + { + case 0: + arg_cpu =3D argv[i]; + break; + case 1: + arg_human =3D strcmp (argv[i], "ide"); /* default human */ + break; + } + } + + /* Fill BUF with monitor command. */ + snprintf ((char *) ui_buf.buf, ui_buf.buf_size, "set %s profiling ide-qu= ery", + args =3D=3D NULL ? "cpu" : arg_cpu); + target_rcmd ((char *) ui_buf.buf, res); + memset (ui_buf.buf, 0, ui_buf.buf_size); + ui_file_put (res, do_ui_file_put_memcpy, &ui_buf); + + if (!arg_human) + { + fprintf_unfiltered (gdb_stdtarg, + "=3Dprofiling,reason=3D\"fast_l1_profiling\",data=3D\"%s\"\n", + ui_buf.buf); + goto bye; + } + + /* The first response is Row=3D%d;Column=3D%d; + and then comes 'Row' rows, including head row */ + i =3D sscanf ((char *) ui_buf.buf, "Row=3D%d;Column=3D%d;", &row, &col); + if (i !=3D 2) + error (_("Failed to query profiling data")); + + p =3D (char *) ui_buf.buf; + + /* Skip "Row=3Dr;Column=3Dc;". */ + for (i =3D 0; i < 2 && p; i++) + p =3D strchr (p + 1, ';'); + p++; + + /* Print human-mode table here. */ + nds32_print_human_table (col, row, p); + +bye: + do_cleanups (back_to); +} + +/* Callback for "nds32 query perfmeter" command. */ + +static void +nds32_query_perfmeter_command (char *args, int from_tty) +{ + /* For perfmeter, there will be only one response. */ + char cmd[128]; + + snprintf (cmd, sizeof (cmd), "set %s perf-meter query", + args =3D=3D NULL ? "cpu" : args); + target_rcmd (cmd, gdb_stdtarg); +} + +/* Callback for "nds32 reset profiling" command. */ + +static void +nds32_reset_profiling_command (char *args, int from_tty) +{ + char cmd[256]; + + snprintf (cmd, sizeof (cmd), "set %s profiling reset", + args =3D=3D NULL ? "cpu" : args); + target_rcmd (cmd, gdb_stdtarg); +} + +/* Callback for "nds32 reset perfmeter" command. */ + +static void +nds32_reset_perfmeter_command (char *args, int from_tty) +{ + char cmd[256]; + + snprintf (cmd, sizeof (cmd), "set %s perf-meter reset", + args =3D=3D NULL ? "cpu" : args); + target_rcmd (cmd, gdb_stdtarg); +} + +static void +nds32_remote_info_init (void) +{ + nds32_remote_info.type =3D nds32_rt_unknown; + nds32_remote_info.endian =3D BFD_ENDIAN_UNKNOWN; + strcpy (nds32_remote_info.cpu, "cpu"); +} + +/* Query target information. */ + +static struct value * +nds32_target_type_make_value (struct gdbarch *gdbarch, struct internalvar = *var, + void *ignore) +{ + int val =3D 0; + + if (strcmp (target_shortname, "remote") =3D=3D 0 + || strcmp (target_shortname, "extended-remote") =3D=3D 0) + val =3D target_has_registers ? nds32_remote_info.type + : nds32_rt_unknown; + + return value_from_longest (builtin_type (gdbarch)->builtin_int, + val); +} + +static int +nds32_query_target_using_qpart (void) +{ + char *buf; + long size =3D 64; + struct cleanup *back_to; + int ret =3D FALSE; + + /* The buffer passed to getpkt must be allocated using xmalloc, + because it might be xrealloc by read_frame. + See remote.c for details. `buf' must be freed before return. */ + buf =3D xmalloc (size); + + /* Let caller clean it up. */ + back_to =3D make_cleanup (free_current_contents, &buf); + + /* qPart:nds32:ask:target - SID or ICE. */ + nds32_remote_info.type =3D nds32_rt_unknown; + putpkt (nds32_qparts[NDS32_Q_TARGET]); + getpkt (&buf, &size, 0); + if (strcmp (buf, "SID") =3D=3D 0) + nds32_remote_info.type =3D nds32_rt_sid; + else if (strcmp (buf, "ICE") =3D=3D 0) + nds32_remote_info.type =3D nds32_rt_ice; + else + goto out; + + /* qPart:nds32:ask:cpu - prompt, e.g., "core0(gdb) ". */ + putpkt (nds32_qparts[NDS32_Q_CPU]); + getpkt (&buf, &size, 0); + if (strlen (buf) > 0 && buf[0] !=3D 'E') + { + const int csize =3D sizeof (nds32_remote_info.cpu); + memset (nds32_remote_info.cpu, 0, csize); + strncpy (nds32_remote_info.cpu, buf, csize - 1); + } + + /* qPart:nds32:ask:de - endian, e.g., LE or BE. */ + putpkt (nds32_qparts[NDS32_Q_ENDIAN]); + getpkt (&buf, &size, 0); + if (strcmp (buf, "LE") =3D=3D 0) + nds32_remote_info.endian =3D BFD_ENDIAN_LITTLE; + else if (strcmp (buf, "BE") =3D=3D 0) + nds32_remote_info.endian =3D BFD_ENDIAN_BIG; + else + nds32_remote_info.endian =3D BFD_ENDIAN_UNKNOWN; + ret =3D TRUE; + +out: + do_cleanups (back_to); + return ret; +} + +static int +nds32_query_target_using_qrcmd (void) +{ + struct cleanup *back_to; + struct ui_file *res; + struct ui_file_buffer ui_buf; + char buf[64]; + int ret =3D FALSE; + volatile struct gdb_exception except; + int len; + + /* ui_file for qRcmd. */ + res =3D mem_fileopen (); + back_to =3D make_cleanup_ui_file_delete (res); + + /* ui_file_buffer for reading ui_file. */ + ui_buf.buf_size =3D 64; + ui_buf.buf =3D xmalloc (ui_buf.buf_size); + make_cleanup (free_current_contents, &ui_buf.buf); + + /* make_cleanup outside TRY_CACHE, + because it save and reset cleanup-chain. */ + make_cleanup_restore_ui_file (&gdb_stdtarg); + /* Supress error messages from gdbserver + if gdbserver doesn't support the monitor command. */ + gdb_stdtarg =3D res; + + TRY_CATCH (except, RETURN_MASK_ERROR) + { + target_rcmd ("nds query target", res); + } + if (except.reason < 0) + goto out; + + /* Read data in ui_file. */ + memset (ui_buf.buf, 0, ui_buf.buf_size); + ui_file_put (res, do_ui_file_put_memcpy, &ui_buf); + + /* Trim trailing newline characters. */ + len =3D strlen ((char *) ui_buf.buf); + while (isspace (ui_buf.buf[len - 1]) && len > 0) + len--; + ui_buf.buf[len] =3D '\0'; + + if (strcmp ((char *) ui_buf.buf, "OCD") =3D=3D 0) + nds32_remote_info.type =3D nds32_rt_ocd; + else + { + printf_unfiltered (_("Unknown remote target %s\n"), + ui_buf.buf); + goto out; + } + + ret =3D TRUE; +out: + do_cleanups (back_to); + return ret; +} + +static void +nds32_query_target_command (char *arg, int from_tty) +{ + nds32_remote_info_init (); + + if (strcmp (target_shortname, "remote") !=3D 0) + return; + /* FIXME if we don't know, use ELF. */ + + /* Try to find out the type of target - SID, ICE or OCD. */ + if (!nds32_query_target_using_qpart ()) + nds32_query_target_using_qrcmd (); + +end_query: + /* Set cpu name if ICE and CPU!=3D"cpu". */ + if (strcmp ("cpu", nds32_remote_info.cpu) !=3D 0) + { + char buf[64]; + snprintf (buf, sizeof (buf), "%s(gdb) ", nds32_remote_info.cpu); + set_prompt (buf); + } + else + { + /* Restore to DEFAULT_PROMPT. */ + set_prompt ("(gdb) "); + } +} + +/* This is only used for SID. Set command-line string. */ + +static void +nds32_set_gloss_command (char *arg, int from_tty) +{ + int i; + struct ui_file *out; + char *arg0; + char *args; + char *f; + char cmdline[0x1000]; /* 4K for max command line. */ + struct cleanup *back_to; + asection *s =3D NULL; + const char *sectnames[] =3D { ".text", "code", ".bss", "bss" }; + + /* set gloss for SID only. */ + if (nds32_remote_info.type !=3D nds32_rt_sid) + return; + + back_to =3D make_cleanup (null_cleanup, 0); + if (exec_bfd =3D=3D NULL) + error (_("Cannot set gloss without executable.\n" + "Use the \"file\" or \"exec-file\" command.")); + + /* ui_file for target_rcmd. */ + out =3D stdio_fileopen (stdout); + make_cleanup_ui_file_delete (out); + + /* start_code, end_code, start_bss, end_bss, + brk, command-line. */ + for (s =3D exec_bfd->sections; s; s =3D s->next) + { + bfd_vma start, size; + const char *attr; + + for (i =3D 0; i < ARRAY_SIZE (sectnames); i +=3D 2) + if (strcmp (bfd_get_section_name (exec_bfd, s), sectnames[i]) =3D=3D 0) + break; + + if (i >=3D ARRAY_SIZE (sectnames)) + continue; + + start =3D bfd_get_section_vma (exec_bfd, s); + size =3D bfd_section_size (exec_bfd, s); + + /* Set gloss (start|end)_XXX. */ + snprintf (cmdline, sizeof (cmdline), "set gloss start_%s %u", + sectnames[i + 1], (unsigned int) start); + target_rcmd (cmdline, out); + snprintf (cmdline, sizeof (cmdline), "set gloss end_%s %u", + sectnames[i + 1], (unsigned int) (start + size)); + target_rcmd (cmdline, out); + } + + /* Set gloss command-line for "set args". */ + arg0 =3D bfd_get_filename(exec_bfd); + args =3D get_inferior_args (); + + f =3D strrchr (arg0, '/'); + if (f =3D=3D NULL) + f =3D strrchr (arg0, '\\'); + + if (f =3D=3D NULL) + f =3D "a.out"; + else + f++; /* skip separator. */ + + snprintf (cmdline, sizeof (cmdline), + "set gloss command-line \"%s %s\"", f, args); + target_rcmd (cmdline, out); + + do_cleanups (back_to); +} + +static struct cmd_list_element *nds32_pipeline_cmdlist; +static struct cmd_list_element *nds32_query_cmdlist; +static struct cmd_list_element *nds32_reset_cmdlist; +static struct cmd_list_element *nds32_maint_cmdlist; + +static const struct internalvar_funcs nds32_target_type_funcs =3D +{ + nds32_target_type_make_value, + NULL, + NULL +}; + +void +nds32_init_remote_cmds (void) +{ + nds32_remote_info_init (); + + /* nds32 set-gloss COMMAND_LINE */ + add_cmd ("set-gloss", class_files, nds32_set_gloss_command, + _("Check elf/target compatibility before loading. " + "Throwing error if failed."), + &nds32_cmdlist); + + /* nds32 reset-target */ + add_cmd ("reset-target", no_class, nds32_reset_target_command, + _("Turn on pipeline for profiling."), &nds32_cmdlist); + /* nds32 reset-hold */ + add_cmd ("reset-hold", no_class, nds32_reset_hold_command, + _("Turn off pipeline for profiling."), &nds32_cmdlist); + + /* nds32 pipeline (on|off) */ + add_prefix_cmd ("pipeline", no_class, nds32_pipeline_command, + _("nds32-sid profiling commands."), + &nds32_pipeline_cmdlist, "nds32 ", 0, &nds32_cmdlist); + add_cmd ("on", no_class, nds32_pipeline_on_command, + _("Turn on pipeline for profiling."), &nds32_pipeline_cmdlist); + add_cmd ("off", no_class, nds32_pipeline_off_command, + _("Turn off pipeline for profiling."), &nds32_pipeline_cmdlist); + + /* nds32 query (profiling|perf-meter|target) */ + add_prefix_cmd ("query", no_class, nds32_query_command, + _("Query remote data."), &nds32_query_cmdlist, "query ", + 0, &nds32_cmdlist); + add_cmd ("profiling", no_class, nds32_query_profiling_command, + _("Query profiling results."), &nds32_query_cmdlist); + add_cmd ("perf-meter", no_class, nds32_query_perfmeter_command, + _("Query perf-meter results."), &nds32_query_cmdlist); + add_cmd ("target", no_class, nds32_query_target_command, + _("Query target information."), &nds32_query_cmdlist); + + /* nds32 reset (profiling|perf-meter) */ + add_prefix_cmd ("reset", no_class, nds32_reset_command, + _("Reset profiling."), &nds32_reset_cmdlist, "reset ", + 0, &nds32_cmdlist); + add_cmd ("profiling", no_class, nds32_reset_profiling_command, + _("Query profiling results."), &nds32_reset_cmdlist); + add_cmd ("perf-meter", no_class, nds32_reset_perfmeter_command, + _("Query perf-meter results."), &nds32_reset_cmdlist); + + create_internalvar_type_lazy ("_nds32_target_type", &nds32_target_type_f= uncs, + NULL); +} diff --git a/gdb/nds32-remote.h b/gdb/nds32-remote.h new file mode 100644 index 0000000..629f8b6 --- /dev/null +++ b/gdb/nds32-remote.h @@ -0,0 +1,28 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#ifndef NDS32_REMOTE_H +#define NDS32_REMOTE_H + +void nds32_init_remote_cmds (void); +void nds32_remote_breakpoint_from_pc (struct gdbarch *gdbarch, + CORE_ADDR *pcptr, int *kindptr); + +#endif diff --git a/gdb/nds32-tdep.c b/gdb/nds32-tdep.c new file mode 100644 index 0000000..f861807 --- /dev/null +++ b/gdb/nds32-tdep.c @@ -0,0 +1,2802 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#include +#include + +#include "defs.h" +#include "frame.h" +#include "frame-unwind.h" +#include "frame-base.h" +#include "symtab.h" +#include "gdbtypes.h" +#include "gdbcmd.h" +#include "gdbcore.h" +#include "gdb_string.h" +#include "value.h" +#include "reggroups.h" +#include "inferior.h" +#include "symfile.h" +#include "objfiles.h" +#include "osabi.h" +#include "language.h" +#include "arch-utils.h" +#include "regcache.h" +#include "trad-frame.h" +#include "dis-asm.h" +#include "gdb_assert.h" +#include "user-regs.h" +#include "elf-bfd.h" +#include "dwarf2-frame.h" +#include "ui-file.h" +#include "remote.h" +#include "target-descriptions.h" +#include "sim-regno.h" +#include "gdb/sim-nds32.h" + +#include "nds32-tdep.h" +#include "nds32-utils.h" +#include "nds32-remote.h" +#include "elf/nds32.h" +#include "opcode/nds32.h" + +/* Simple macro for chop LSB immediate bits from an instruction. */ +#define CHOP_BITS(insn, n) (insn & ~__MASK (n)) + +extern void _initialize_nds32_tdep (void); + +struct nds32_gdb_config nds32_config; + +/* The standard register names. */ +static char *nds32_regnames[] =3D +{ + /* 32 GPRs. */ + "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", "fp", "gp", "lp", "sp", + + /* 5 User Registers. */ + "pc", "d0lo", "d0hi", "d1lo", "d1hi", +}; + +/* Mnemonic names for registers. */ +struct nds32_register_alias +{ + const char *name; + const char *alias; +}; + +/* Register alias for user_reg_map_name_to_regnum (). */ +struct nds32_register_alias nds32_register_aliases[] =3D +{ + {"r15", "ta"}, + {"r26", "p0"}, + {"r27", "p1"}, + {"fp", "r28"}, + {"gp", "r29"}, + {"lp", "r30"}, + {"sp", "r31"}, + + {"ir0", "psw"}, + {"ir1", "ipsw"}, + {"ir2", "p_psw"}, + {"ir3", "ivb"}, + {"ir4", "eva"}, + {"ir5", "p_eva"}, + {"ir6", "itype"}, + {"ir7", "p_itype"}, + {"ir8", "merr"}, + {"ir9", "ipc"}, + {"ir10", "p_ipc"}, + {"ir11", "oipc"}, + {"ir12", "p_p0"}, + {"ir13", "p_p1"}, + {"ir14", "int_mask"}, + {"ir15", "int_pend"}, + + {"cr0", "cpu_ver"}, + {"cr1", "icm_cfg"}, + {"cr2", "dcm_cfg"}, + {"cr3", "mmu_cfg"}, + {"cr4", "msc_cfg"}, + {"cr5", "core_id"}, + {"cr6", "fucop_exist"}, + + {"mr0", "mmu_ctl"}, + {"mr1", "l1_pptb"}, + {"mr2", "tlb_vpn"}, + {"mr3", "tlb_data"}, + {"mr4", "tlb_misc"}, + {"mr5", "vlpt_idx"}, + {"mr6", "ilmb"}, + {"mr7", "dlmb"}, + {"mr8", "cache_ctl"}, + {"mr9", "hsmp_saddr"}, + {"mr10", "hsmp_eaddr"}, + + {"pfr0", "pfmc0"}, + {"pfr1", "pfmc1"}, + {"pfr2", "pfmc2"}, + {"pfr3", "pfm_ctl"}, + + {"dmar0", "dma_cfg"}, + {"dmar1", "dma_gcsw"}, + {"dmar2", "dma_chnsel"}, + {"dmar3", "dma_act"}, + {"dmar4", "dma_setup"}, + {"dmar5", "dma_isaddr"}, + {"dmar6", "dma_esaddr"}, + {"dmar7", "dma_tcnt"}, + {"dmar8", "dma_status"}, + {"dmar9", "dma_2dset"}, + {"dmar10", "dma_2dsctl"}, +}; + +/* Value of a register alias. BATON is register name of the alias, + because system registers do not have fixed register number. + We must look-up them when access. */ + +static struct value * +nds32_value_of_reg (struct frame_info *frame, const void *baton) +{ + struct gdbarch *gdbarch =3D get_frame_arch (frame); + int regnum; + + regnum =3D user_reg_map_name_to_regnum (gdbarch, (const char *) baton, -= 1); + + return value_of_register (regnum, frame); +} + +/* gdbarch_frame_align () */ + +static CORE_ADDR +nds32_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) +{ + /* 8-byte aligned. */ + return sp & ~(8 - 1); +} + +/* Implement the gdbarch_breakpoint_from_pc method. */ + +static const gdb_byte * +nds32_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, + int *lenptr) +{ + static const gdb_byte NDS32_BREAK16[] =3D { 0xEA, 0x00 }; + const unsigned char *bp; + + gdb_assert (pcptr); + gdb_assert (lenptr); + + if ((*pcptr) & 1) + error (_("Bad address %p for inserting breakpoint.\n" + "Address must be at least 2-byte aligned."), (void *) *pcptr); + + /* Always insert 16-bit break instruction. */ + *lenptr =3D 2; + return NDS32_BREAK16; +} + +/* Implement the gdbarch_dwarf2_reg_to_regnum method. + Map DWARF regnum from GCC to GDB regnum. */ + +static int +nds32_dwarf_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num) +{ + const int GPR =3D 0; + const int DXR =3D 34; + const int FSR =3D 38; + const int FDR =3D FSR + 32; + + if (num >=3D 0 && num < 32) /* R0 - R31 */ + return num; + else if (num >=3D DXR && num < DXR + 4) /* D0/D1 */ + return num - DXR + NDS32_D0LO_REGNUM; + else if (num >=3D FSR && num < FSR + 32) /* FS */ + return num - FSR + user_reg_map_name_to_regnum (gdbarch, "fs0", + strlen ("fs0")); + else if (num >=3D FDR && num < FDR + 32) /* FD */ + return num - FDR + user_reg_map_name_to_regnum (gdbarch, "fd0", + strlen ("fd0")); + + /* No match, return a inaccessible register number. */ + return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch); +} + +static int +nds32_register_sim_regno (struct gdbarch *gdbarch, int regnum) +{ + const char *reg_name; + /* Use target-descriptions for register mapping. */ + + /* Only makes sense to supply raw registers. */ + gdb_assert (regnum >=3D 0 && regnum < gdbarch_num_regs (gdbarch)); + + if (regnum < NDS32_NUM_REGS) + return regnum; + if (regnum >=3D NDS32_SIM_FD0_REGNUM && regnum < NDS32_SIM_FD0_REGNUM + = 32) + return SIM_NDS32_FD0_REGNUM + regnum - NDS32_SIM_FD0_REGNUM; + switch (regnum) + { + case NDS32_SIM_IFCLP_REGNUM: + return SIM_NDS32_IFCLP_REGNUM; + case NDS32_SIM_ITB_REGNUM: + return SIM_NDS32_ITB_REGNUM; + case NDS32_SIM_PSW_REGNUM: + return SIM_NDS32_PSW_REGNUM; + } + + return LEGACY_SIM_REGNO_IGNORE; +} + +/* Create types for registers and insert them to type table by name. */ + +static void +nds32_alloc_types (struct gdbarch *gdbarch) +{ + const struct builtin_type *bt =3D builtin_type (gdbarch); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + struct type *type, *stype1, *stype2; + + tdep->type_tab =3D nds32_alloc_type_tab (24); + + /* fucpr */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_fucpr", 4); + append_flags_type_flag (type, 0, "CP0EN"); + append_flags_type_flag (type, 1, "CP1EN"); + append_flags_type_flag (type, 2, "CP2EN"); + append_flags_type_flag (type, 3, "CP3EN"); + append_flags_type_flag (type, 31, "AUEN"); + nds32_type_insert (tdep->type_tab, "fucpr", type); + + /* fpcfg */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_fpcfg"); + nds32_append_enum (type, 0, "8SP_4DP"); + nds32_append_enum (type, 1, "16SP_8DP"); + nds32_append_enum (type, 2, "32SP_16DP"); + nds32_append_enum (type, 3, "32SP_32DP"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_fpcfg_type", USE_FLAGS); + nds32_append_flag (type, 0, "SP"); + nds32_append_flag (type, 1, "DP"); + nds32_append_bitfield (type, stype1, 2, 3, "FREG"); + nds32_append_flag (type, 4, "FMA"); + nds32_append_bitfield (type, bt->builtin_uint8, 22, 26, "IMVER"); + nds32_append_bitfield (type, bt->builtin_uint8, 27, 31, "AVER"); + nds32_type_insert (tdep->type_tab, "fpcfg", type); + + /* fpcsr */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_fpcsr_rm"); + nds32_append_enum (type, 0, "RTNE"); + nds32_append_enum (type, 1, "RTPI"); + nds32_append_enum (type, 2, "RTMI"); + nds32_append_enum (type, 3, "RTZ"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_fpcsr", USE_FLAGS= ); + nds32_append_bitfield (type, stype1, 0, 1, "RM"); + nds32_append_flag (type, 2, "IVO"); + nds32_append_flag (type, 3, "DBZ"); + nds32_append_flag (type, 4, "OVF"); + nds32_append_flag (type, 5, "UDF"); + nds32_append_flag (type, 6, "IEX"); + nds32_append_flag (type, 7, "IVOE"); + nds32_append_flag (type, 8, "DBZE"); + nds32_append_flag (type, 9, "OVFE"); + nds32_append_flag (type, 10, "UDFE"); + nds32_append_flag (type, 11, "IEXE"); + nds32_append_flag (type, 12, "DNZ"); + nds32_append_flag (type, 13, "IVOT"); + nds32_append_flag (type, 14, "DBZT"); + nds32_append_flag (type, 15, "OVFT"); + nds32_append_flag (type, 16, "UDFT"); + nds32_append_flag (type, 17, "IEXT"); + nds32_append_flag (type, 18, "DNIT"); + nds32_append_flag (type, 19, "RIT"); + nds32_type_insert (tdep->type_tab, "fpcsr", type); + + /* ir0 - processor status word register + ir1 - interruption PSW register + ir2 - previous IPSW register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_psw_intl"); + nds32_append_enum (type, 0, "NO"); + nds32_append_enum (type, 1, "Lv1"); + nds32_append_enum (type, 2, "Lv2"); + nds32_append_enum (type, 3, "Lv3"); + stype1 =3D type; + + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_psw_pow"); + nds32_append_enum (type, 0, "User"); + nds32_append_enum (type, 1, "Superuser"); + nds32_append_enum (type, 2, "Reserved(2)"); + nds32_append_enum (type, 3, "Reserved(3)"); + stype2 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_psw", USE_FLAGS); + nds32_append_flag (type, 0, "GIE"); + nds32_append_bitfield (type, stype1, 1, 2, "INTL"); + nds32_append_bitfield (type, stype2, 3, 4, "POM"); + nds32_append_flag (type, 5, "BE"); + nds32_append_flag (type, 6, "IT"); + nds32_append_flag (type, 7, "DT"); + nds32_append_flag (type, 8, "IME"); + nds32_append_flag (type, 9, "DME"); + nds32_append_flag (type, 10, "DEX"); + nds32_append_flag (type, 11, "HSS"); + nds32_append_flag (type, 12, "DRBE"); + nds32_append_flag (type, 13, "AEN"); + nds32_append_flag (type, 14, "WBNA"); + nds32_append_flag (type, 15, "IFCON"); + nds32_append_flag (type, 20, "OV"); + nds32_type_insert (tdep->type_tab, "ir0", type); + nds32_type_insert (tdep->type_tab, "ir1", type); + nds32_type_insert (tdep->type_tab, "ir2", type); + + /* ir3 - Interrupt Vector Base Register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_ivb_esz"); + nds32_append_enum (type, 0, "4_byte"); + nds32_append_enum (type, 1, "16_byte"); + nds32_append_enum (type, 2, "64_byte"); + nds32_append_enum (type, 3, "256_byte"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_ivb", USE_FLAGS); + nds32_append_flag (type, 13, "EVIC"); + nds32_append_bitfield (type, stype1, 14, 15, "ESZ"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "IVBASE"); + nds32_type_insert (tdep->type_tab, "ir3", type); + + /* ir6 - Interruption Type Register + ir7 - Previous ITYPE */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_itype", USE_FLAGS= ); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 3, "ETYPE"); + nds32_append_flag (type, 4, "INST"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 30, "SWID"); + nds32_type_insert (tdep->type_tab, "ir6", type); + nds32_type_insert (tdep->type_tab, "ir7", type); + + /* ir14 - Interruption Masking Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_int_mask", 4); + append_flags_type_flag (type, 0, "H0IM"); + append_flags_type_flag (type, 1, "H1IM"); + append_flags_type_flag (type, 2, "H2IM"); + append_flags_type_flag (type, 3, "H3IM"); + append_flags_type_flag (type, 4, "H4IM"); + append_flags_type_flag (type, 5, "H5IM"); + append_flags_type_flag (type, 16, "SIM"); + append_flags_type_flag (type, 29, "ALZ"); + append_flags_type_flag (type, 30, "IDIVZE"); + append_flags_type_flag (type, 31, "DSSIM"); + nds32_type_insert (tdep->type_tab, "ir14", type); + + /* ir18 - Interruption Prioirty Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_int_pri", NO_FLAG= S); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "H0PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 2, 3, "H1PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 4, 5, "H2PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 6, 7, "H3PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 8, 9, "H4PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 10, 11, "H5PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 12, 13, "H6PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 14, 15, "H7PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 16, 17, "H8PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 18, 19, "H9PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 20, 21, "H10PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 22, 23, "H11PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 24, 25, "H12PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 26, 27, "H13PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 28, 29, "H14PRI"); + nds32_append_bitfield (type, bt->builtin_uint8, 30, 31, "H15PRI"); + nds32_type_insert (tdep->type_tab, "ir18", type); + + /* mr0 - MMU Control Register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_mmuctl_ntc"); + nds32_append_enum (type, 0, "NCA_NCO"); + nds32_append_enum (type, 1, "NCA_CO"); + nds32_append_enum (type, 2, "CA_WB"); + nds32_append_enum (type, 3, "CA_WT"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_mmu_ctl", USE_FLA= GS); + nds32_append_flag (type, 0, "D"); + nds32_append_bitfield (type, stype1, 1, 2, "NTC0"); + nds32_append_bitfield (type, stype1, 3, 4, "NTC1"); + nds32_append_bitfield (type, stype1, 5, 6, "NTC2"); + nds32_append_bitfield (type, stype1, 7, 8, "NTC3"); + nds32_append_flag (type, 9, "TBALCK"); + nds32_append_flag (type, 10, "MPZIU"); + nds32_append_bitfield (type, bt->builtin_uint8, 11, 12, "NTM0"); + nds32_append_bitfield (type, bt->builtin_uint8, 13, 14, "NTM1"); + nds32_append_bitfield (type, bt->builtin_uint8, 15, 16, "NTM2"); + nds32_append_bitfield (type, bt->builtin_uint8, 17, 18, "NTM3"); + nds32_append_flag (type, 19, "DREE"); + nds32_type_insert (tdep->type_tab, "mr0", type); + + /* mr1 */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_l1_pptb", USE_FLA= GS); + nds32_append_flag (type, 0, "NV"); + nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "L1_PPT_BASE"); + nds32_type_insert (tdep->type_tab, "mr1", type); + + /* mr2 */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_tlb_vpn", NO_FLAG= S); + nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "VPN"); + nds32_type_insert (tdep->type_tab, "mr2", type); + + /* mr3 */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_tlb_data", USE_FL= AGS); + nds32_append_flag (type, 0, "V"); + nds32_append_bitfield (type, bt->builtin_uint8, 1, 3, "M"); + nds32_append_flag (type, 4, "D"); + nds32_append_flag (type, 5, "X"); + nds32_append_flag (type, 6, "A"); + nds32_append_flag (type, 7, "G"); + nds32_append_bitfield (type, bt->builtin_uint8, 8, 10, "C"); + nds32_append_bitfield (type, bt->builtin_uint32, 12, 31, "PPN"); + nds32_type_insert (tdep->type_tab, "mr3", type); + + /* mr4 - TLB Access Misc Register */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_tlb_misc_acc_psz"= ); + nds32_append_enum (type, 0, "4KB"); + nds32_append_enum (type, 1, "8KB"); + nds32_append_enum (type, 2, "16KB"); + nds32_append_enum (type, 3, "64KB"); + nds32_append_enum (type, 4, "256KB"); + nds32_append_enum (type, 5, "1MB"); + nds32_append_enum (type, 6, "4MB"); + nds32_append_enum (type, 7, "16MB"); + nds32_append_enum (type, 8, "64MB"); + nds32_append_enum (type, 9, "256MB"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_tlb_misc", NO_FLA= GS); + nds32_append_bitfield (type, stype1, 0, 3, "ACC_PSZ"); + nds32_append_bitfield (type, bt->builtin_uint32, 4, 12, "CID"); + nds32_type_insert (tdep->type_tab, "mr4", type); + + /* mr6 */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_ilm_size"); + nds32_append_enum (type, 0, "4KB"); + nds32_append_enum (type, 1, "8KB"); + nds32_append_enum (type, 2, "16KB"); + nds32_append_enum (type, 3, "32KB"); + nds32_append_enum (type, 4, "64KB"); + nds32_append_enum (type, 5, "128KB"); + nds32_append_enum (type, 6, "256KB"); + nds32_append_enum (type, 7, "512KB"); + nds32_append_enum (type, 8, "1024KB"); + nds32_append_enum (type, 9, "1KB"); + nds32_append_enum (type, 10, "2KB"); + nds32_append_enum (type, 15, "0KB"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_ilmb", NO_FLAGS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "IEN"); + nds32_append_bitfield (type, stype1, 1, 4, "ILMSZ"); + nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)"); + nds32_type_insert (tdep->type_tab, "mr6", type); + + /* mr7 */ + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_dlm_size"); + nds32_append_enum (type, 0, "4KB"); + nds32_append_enum (type, 1, "8KB"); + nds32_append_enum (type, 2, "16KB"); + nds32_append_enum (type, 3, "32KB"); + nds32_append_enum (type, 4, "64KB"); + nds32_append_enum (type, 5, "128KB"); + nds32_append_enum (type, 6, "256KB"); + nds32_append_enum (type, 7, "512KB"); + nds32_append_enum (type, 8, "1024KB"); + nds32_append_enum (type, 9, "1KB"); + nds32_append_enum (type, 10, "2KB"); + nds32_append_enum (type, 15, "0KB"); + stype1 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_dlmb", NO_FLAGS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 0, "DEN"); + nds32_append_bitfield (type, stype1, 1, 4, "DLMSZ"); + nds32_append_bitfield (type, bt->builtin_uint8, 5, 5, "DBM"); + nds32_append_bitfield (type, bt->builtin_uint8, 6, 6, "DBB"); + nds32_append_bitfield (type, bt->builtin_data_ptr, 0, 31, "(raw)"); + nds32_type_insert (tdep->type_tab, "mr7", type); + + /* mr8 - Cache Control Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_cache_ctl", 4); + append_flags_type_flag (type, 0, "IC_EN"); + append_flags_type_flag (type, 1, "DC_EN"); + append_flags_type_flag (type, 2, "ICALCK"); + append_flags_type_flag (type, 3, "DCALCK"); + append_flags_type_flag (type, 4, "DCCWF"); + append_flags_type_flag (type, 5, "DCPMW"); + nds32_type_insert (tdep->type_tab, "mr8", type); + + /* dr40 - EDM Configuration Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_edm_cfg", USE_FLA= GS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 2, "BC"); + nds32_append_flag (type, 3, "DIMU"); + nds32_append_flag (type, 4, "DALM"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER"); + nds32_type_insert (tdep->type_tab, "dr40", type); + + /* dmar0 - DMA Configuration Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_dma_cfg", USE_FLA= GS); + nds32_append_bitfield (type, bt->builtin_uint8, 0, 1, "NCHN"); + nds32_append_flag (type, 2, "UNEA"); + nds32_append_flag (type, 3, "2DET"); + nds32_append_bitfield (type, bt->builtin_uint16, 16, 31, "VER"); + nds32_type_insert (tdep->type_tab, "dmar0", type); + + /* cr0 - CPU Version Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_cpuver_cfgid", 2); + append_flags_type_flag (type, 0, "PERF_EXT"); + append_flags_type_flag (type, 1, "16_EXT"); + append_flags_type_flag (type, 2, "PERF_EXT2"); + append_flags_type_flag (type, 3, "COP_EXT"); + append_flags_type_flag (type, 4, "STR_EXT"); + stype1 =3D type; + + type =3D nds32_init_enum (gdbarch, "builtin_type_nds32_cpuver_cpuid"); + nds32_append_enum (type, 0x8, "N8"); + nds32_append_enum (type, 0x9, "N9"); + nds32_append_enum (type, 0xA, "N10"); + nds32_append_enum (type, 0xC, "N12"); + nds32_append_enum (type, 0xD, "N13"); + nds32_append_enum (type, 0xE, "N14"); + stype2 =3D type; + + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_cpuver", NO_FLAGS= ); + nds32_append_bitfield (type, stype1, 0, 15, "CFGID"); + nds32_append_bitfield (type, bt->builtin_uint8, 16, 23, "REV"); + nds32_append_bitfield (type, stype2, 24, 31, "CPUID"); + nds32_type_insert (tdep->type_tab, "cr0", type); + + /* cr4 - Misc Configuration Register */ + type =3D nds32_init_type (gdbarch, "builtin_type_nds32_msc_cfg", USE_FLA= GS); + nds32_append_flag (type, 0, "EDM"); + nds32_append_flag (type, 1, "LMDMA"); + nds32_append_flag (type, 2, "PFM"); + nds32_append_flag (type, 3, "HSMP"); + nds32_append_flag (type, 4, "TRACE"); + nds32_append_flag (type, 5, "DIV"); + nds32_append_flag (type, 6, "MAC"); + nds32_append_bitfield (type, bt->builtin_uint8, 7, 8, "AUDIO"); + nds32_append_flag (type, 9, "L2c"); + nds32_append_flag (type, 10, "RDREG"); + nds32_append_flag (type, 11, "ADR24"); + nds32_append_flag (type, 12, "INTLC"); + nds32_append_bitfield (type, bt->builtin_uint8, 13, 15, "BASEV"); + nds32_append_flag (type, 16, "NOD"); + nds32_append_flag (type, 17, "IMV"); + nds32_append_flag (type, 18, "IMR"); + nds32_append_flag (type, 19, "IFC"); + nds32_append_flag (type, 20, "MCU"); + nds32_type_insert (tdep->type_tab, "cr4", type); + + /* cr6 - FPU and Coprocessor Existence Configuration Register */ + type =3D arch_flags_type (gdbarch, "builtin_type_nds32_fucop_exist", 4); + append_flags_type_flag (type, 0, "CP0EX"); + append_flags_type_flag (type, 1, "CP1EX"); + append_flags_type_flag (type, 2, "CP2EX"); + append_flags_type_flag (type, 3, "CP3EX"); + append_flags_type_flag (type, 31, "AUEX"); + nds32_type_insert (tdep->type_tab, "cr6", type); +} + +/* gdbarch_register_type () + + Return the GDB type object for the "standard" data type + of data in register N. + It get pretty messy here. I need enum-types and bit-fields + for better representation. But they cannot be done by + tdesc-xml. */ + +static struct type * +nds32_register_type (struct gdbarch *gdbarch, int regnum) +{ + int num_regs =3D gdbarch_num_regs (gdbarch); + const struct builtin_type *bt =3D builtin_type (gdbarch); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + struct type *type; + const char *reg_name; + + /* Currently, only FSR are supported. */ + if (regnum >=3D num_regs && regnum < num_regs + 32) + return builtin_type (gdbarch)->builtin_float; + else if (regnum >=3D num_regs) + return NULL; + + /* NDS32 predefined types for specific registers. */ + if (tdep->type_tab =3D=3D NULL) + nds32_alloc_types (gdbarch); + + reg_name =3D user_reg_map_regnum_to_name (gdbarch, regnum); + if (reg_name =3D=3D NULL) + reg_name =3D ""; + type =3D nds32_type_lookup (tdep->type_tab, reg_name); + if (type) + return type; + + /* Type provided by target-description. */ + if (tdesc_has_registers (gdbarch_target_desc (gdbarch))) + { + type =3D tdesc_register_type (gdbarch, regnum); + if (type) + return type; + } + + /* Floating pointer registers. e.g., fs0 or fd0. */ + if (strlen (reg_name) >=3D 3 && reg_name[0] =3D=3D 'f' && reg_name[2] >= =3D '0' + && reg_name[2] <=3D '9') + { + if (reg_name[1] =3D=3D 's') + return bt->builtin_float; + else if (reg_name[1] =3D=3D 'd') + return bt->builtin_double; + } + + /* GPRs. */ + if (regnum =3D=3D NDS32_PC_REGNUM || regnum =3D=3D NDS32_LP_REGNUM) + return bt->builtin_func_ptr; + else if (regnum =3D=3D NDS32_SP_REGNUM || regnum =3D=3D NDS32_FP_REGNUM + || regnum =3D=3D NDS32_GP_REGNUM) + return bt->builtin_data_ptr; + else if (regnum < 32) + return bt->builtin_int32; + + /* We don't know. Display it in hex-form. */ + return bt->builtin_data_ptr; +} + +/* nds32 register groups. */ +static struct reggroup *nds32_cr_reggroup; +static struct reggroup *nds32_ir_reggroup; +static struct reggroup *nds32_mr_reggroup; +static struct reggroup *nds32_dr_reggroup; +static struct reggroup *nds32_pfr_reggroup; +static struct reggroup *nds32_dmar_reggroup; +static struct reggroup *nds32_racr_reggroup; +static struct reggroup *nds32_idr_reggroup; +static struct reggroup *nds32_audio_reggroup; + +static void +nds32_init_reggroups (void) +{ + /* gpr usr sr */ + nds32_cr_reggroup =3D reggroup_new ("cr", USER_REGGROUP); + nds32_ir_reggroup =3D reggroup_new ("ir", USER_REGGROUP); + nds32_mr_reggroup =3D reggroup_new ("mr", USER_REGGROUP); + nds32_dr_reggroup =3D reggroup_new ("dr", USER_REGGROUP); + nds32_pfr_reggroup =3D reggroup_new ("pfr", USER_REGGROUP); + nds32_dmar_reggroup =3D reggroup_new ("dmar", USER_REGGROUP); + nds32_racr_reggroup =3D reggroup_new ("racr", USER_REGGROUP); + nds32_idr_reggroup =3D reggroup_new ("idr", USER_REGGROUP); + + nds32_audio_reggroup =3D reggroup_new ("audio", USER_REGGROUP); +} + +static void +nds32_add_reggroups (struct gdbarch *gdbarch) +{ + /* Target-independent groups. */ + reggroup_add (gdbarch, general_reggroup); + reggroup_add (gdbarch, float_reggroup); + reggroup_add (gdbarch, all_reggroup); + reggroup_add (gdbarch, system_reggroup); + + /* System register groups. */ + reggroup_add (gdbarch, nds32_cr_reggroup); + reggroup_add (gdbarch, nds32_ir_reggroup); + reggroup_add (gdbarch, nds32_mr_reggroup); + reggroup_add (gdbarch, nds32_dr_reggroup); + reggroup_add (gdbarch, nds32_pfr_reggroup); + reggroup_add (gdbarch, nds32_dmar_reggroup); + reggroup_add (gdbarch, nds32_racr_reggroup); + reggroup_add (gdbarch, nds32_idr_reggroup); +} + +/* Implement the gdbarch_register_reggroup_p method. */ + +static int +nds32_register_reggroup_p (struct gdbarch *gdbarch, int regnum, + struct reggroup *group) +{ + int i; + struct reggroup *groups[] =3D + { + nds32_cr_reggroup, nds32_ir_reggroup, nds32_mr_reggroup, + nds32_dr_reggroup, nds32_pfr_reggroup, nds32_dmar_reggroup, + nds32_racr_reggroup, nds32_idr_reggroup + }; + static const char *prefix[] =3D + { + "cr", "ir", "mr", "dr", "pfr", "dmar", "racr", "idr" + }; + + gdb_assert (sizeof (groups) =3D=3D sizeof (prefix)); + + /* GPRs. */ + if (group =3D=3D general_reggroup) + return regnum <=3D NDS32_PC_REGNUM; + + /* System Registers are grouped by prefix. */ + else if (group =3D=3D system_reggroup) + return (regnum > NDS32_PC_REGNUM) + && TYPE_CODE (register_type (gdbarch, regnum)) !=3D TYPE_CODE_FLT; + + for (i =3D 0; i < ARRAY_SIZE (groups); i++) + { + if (group =3D=3D groups[i]) + { + const char *regname =3D tdesc_register_name (gdbarch, regnum); + + if (!regname) + return 0; + return strstr (regname, prefix[i]) =3D=3D regname; + } + } + + return default_register_reggroup_p (gdbarch, regnum, group); +} + +/* This function is called when + 1. Target-description is used, and the register is pseudo. + 2. Target-description is NOT used, + i. and the target is simulator. + ii. or the target is legacy target. */ + +/* Implement the tdesc_pseudo_register_name method. */ + +static const char * +nds32_register_name (struct gdbarch *gdbarch, int regnum) +{ + static char *fpu_pseudo_names[] =3D + { + "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", + "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15", + "fs16", "fs17", "fs18", "fs19", "fs20", "fs21", "fs22", "fs23", + "fs24", "fs25", "fs26", "fs27", "fs28", "fs29", "fs30", "fs31" + }; + static char *sim_names[] =3D + { + "fd0", "fd1", "fd2", "fd3", "fd4", "fd5", "fd6", "fd7", + "fd8", "fd9", "fd10", "fd11", "fd12", "fd13", "fd14", "fd15", + "fd16", "fd17", "fd18", "fd19", "fd20", "fd21", "fd22", "fd23", + "fd24", "fd25", "fd26", "fd27", "fd28", "fd29", "fd30", "fd31", + "ifclp", "itb", "ir0" + }; + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + int num_regs =3D gdbarch_num_regs (gdbarch); + + /* Currently, only pseudo FSR are supported. */ + if (regnum >=3D num_regs && regnum < num_regs + 32) + return fpu_pseudo_names[regnum - num_regs]; + + /* GPRs. */ + if (regnum < ARRAY_SIZE (nds32_regnames)) + return nds32_regnames[regnum]; + + /* Registers beteen NUM_REGS and SMI_NUM_REGS are + simulator registers. */ + if (regnum >=3D NDS32_NUM_REGS && regnum < NDS32_SIM_NUM_REGS) + return sim_names[regnum - NDS32_NUM_REGS]; + + warning (_("Unknown nds32 pseudo register %d."), regnum); + return NULL; +} + +/* Implement the gdbarch_pseudo_register_read method. + + For legacy target, target-description and FPRs are not support. + Use Rcmd to access FPU registers. */ + +static enum register_status +nds32_pseudo_register_read (struct gdbarch *gdbarch, + struct regcache *regcache, int regnum, + gdb_byte *buf) +{ + char name_buf[8]; + gdb_byte reg_buf[8]; + int offset; + enum register_status status =3D REG_UNKNOWN; + + /* Sanity check. */ + regnum -=3D gdbarch_num_regs (gdbarch); + if (regnum > gdbarch_num_pseudo_regs (gdbarch)) + return status; + + /* Currently, only FSR are supported. */ + if (regnum < 32) + { + int fd_regnum; + + /* fs0 is always the high-part of fd0. */ + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + offset =3D (regnum & 1) ? 4 : 0; + else + offset =3D (regnum & 1) ? 0 : 4; + + sprintf (name_buf, "fd%d", regnum >> 1); + fd_regnum =3D user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + status =3D regcache_raw_read (regcache, fd_regnum, reg_buf); + if (status =3D=3D REG_VALID) + memcpy (buf, reg_buf + offset, 4); + } + + return status; +} + +/* Implement the gdbarch_pseudo_register_write method. */ + +static void +nds32_pseudo_register_write (struct gdbarch *gdbarch, + struct regcache *regcache, int regnum, + const gdb_byte *buf) +{ + char name_buf[8]; + gdb_byte reg_buf[8]; + int offset; + + /* Sanity check. */ + regnum -=3D gdbarch_num_regs (gdbarch); + if (regnum > gdbarch_num_pseudo_regs (gdbarch)) + return; + + /* Currently, only FSR are supported. */ + if (regnum < 32) + { + int fd_regnum; + + /* fs0 is always the high-part of fd0. */ + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + offset =3D (regnum & 1) ? 4 : 0; + else + offset =3D (regnum & 1) ? 0 : 4; + + sprintf (name_buf, "fd%d", regnum >> 1); + fd_regnum =3D user_reg_map_name_to_regnum (gdbarch, name_buf, + strlen (name_buf)); + regcache_raw_read (regcache, fd_regnum, reg_buf); + memcpy (reg_buf + offset, buf, 4); + regcache_raw_write (regcache, fd_regnum, reg_buf); + } + + return; +} + +/* Skip prologue should be conservative, and frame-unwind should be + relative-aggressive.*/ + +static int +nds32_analyze_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, + CORE_ADDR scan_limit, CORE_ADDR *pl_endptr) +{ + uint32_t insn; + CORE_ADDR cpc =3D -1; /* Candidate PC if no suitable PC is found. */ + LONGEST return_value; + + /* If there is no buffer to store result, ignore this prologue decoding.= */ + if (pl_endptr =3D=3D NULL) + { + return 0; + } + + /* Look up end of prologue */ + for (; pc < scan_limit; ) + { + insn =3D read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); + + if ((insn & 0x80000000) =3D=3D 0) + { + /* 32-bit instruction */ + + pc +=3D 4; + if (insn =3D=3D N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP)) + { + /* add $gp, $ta, $gp */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ADDI, REG_SP, REG_SP, 0= )) + { + /* addi $sp, $sp, imm15 */ + cpc =3D pc; + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ADDI, REG_FP, REG_FP, 0= )) + { + /* addi $fp, $sp, imm15 */ + cpc =3D pc; + continue; + } + else if (insn =3D=3D N32_ALU2 (MFUSR, REG_TA, 31, 0)) + { + /* mfusr $ta, PC ; group=3D0, sub=3D0x20=3Dmfusr */ + continue; + } + else if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (MOVI, REG_TA, 0)) + { + /* movi $ta, imm20s */ + continue; + } + else if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (SETHI, REG_GP, 0)) + { + /* sethi $gp, imm20 */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ORI, REG_GP, REG_GP, 0)) + { + /* ori $gp, $gp, imm15 */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI, REG_LP, REG_FP, 0)) + { + /* Unlike swi, we should stop when lwi. */ + /* swi $lp, [$sp + (imm15s<<2)] */ + continue; + } + else if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI_BI, REG_LP, REG_FP,= 0)) + { + /* swi.bi $rt, [$sp], (imm15s<<2) */ + continue; + } + else if (N32_OP6 (insn) =3D=3D N32_OP6_LSMW && (insn & __BIT (5))) + { + /* bit-5 for SMW */ + + /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */ + + int rb, re, ra, enable4, i; + int aligned; + int m =3D 0; + int di; /* dec=3D-1 or inc=3D1 */ + char enb4map[2][4] =3D { + {0, 1, 2, 3} /* smw */, + {3, 1, 2, 0} /* smwa */}; + LONGEST base =3D ~1 + 1; + + rb =3D N32_RT5 (insn); + ra =3D N32_RA5 (insn); + re =3D N32_RB5 (insn); + enable4 =3D (insn >> 6) & 0x0F; + aligned =3D (insn & 3) ? 1 : 0; + di =3D (insn & (1 << 3)) ? -1 : 1; + + switch (ra) + { + case NDS32_FP_REGNUM: + case NDS32_SP_REGNUM: + cpc =3D pc; + continue; /* found and continue */ + default: + break; + } + } + + if (N32_OP6 (insn) =3D=3D N32_OP6_COP && N32_COP_CP (insn) =3D=3D 0 + && (N32_COP_SUB (insn) =3D=3D N32_FPU_FSS + || N32_COP_SUB (insn) =3D=3D N32_FPU_FSD) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* CP shoud be CP0 */ + /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */ + continue; + } + + /* fssi $fst, [$ra + (imm12s << 2)] + fssi.bi $fst, [$ra], (imm12s << 2) + fsdi $fdt, [$ra + (imm12s << 2)] + fsdi.bi $fdt, [$ra], (imm12s << 2) */ + if ((N32_OP6 (insn) =3D=3D N32_OP6_SWC || N32_OP6 (insn) =3D=3D N32_OP6= _SDC) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* BI bit is dont-care. */ + continue; + } + + pc -=3D 4; + break; + } + else + { + /* 16-bit instruction */ + pc +=3D 2; + insn >>=3D 16; + + /* 1. If the instruction is j/b, then we stop + i.e., OP starts with 10, and beqzs8, bnezs8. + 2. If the operations will change sp/fp or based on sp/fp, + then we are in the prologue. + 3. If we don't know what's it, then stop. */ + + if (CHOP_BITS (insn, 10) =3D=3D N16_TYPE10 (ADDI10S, 0)) + { + /* addi10s */ + continue; + } + else if (__GF (insn, 7, 8) =3D=3D N16_T25_PUSH25) + { + /* push25 */ + continue; + } + else if (insn =3D=3D N16_TYPE55 (MOV55, REG_FP, REG_SP)) + { + /* mov55 fp, sp */ + continue; + } + + /* swi450 */ + switch (insn & ~__MF (-1, 5, 4)) + { + case N16_TYPE45 (SWI450, 0, REG_SP): + case N16_TYPE45 (SWI450, 0, REG_FP): + break; + } + /* swi37 - implied fp */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37 + && (insn & __BIT (7))) + continue; + + /* swi37sp - implied */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37SP + && (insn & __BIT (7))) + continue; + + /* If the a instruction is not accepted, + don't go futher. */ + pc -=3D 2; + break; + } + } + + if (pc >=3D scan_limit) + { + /* If we can not find end of prologue before scan_limit, + we assume that end of prologue is on pc_after_stack_adject. */ + if (cpc !=3D -1) + pc =3D cpc; + } + + *pl_endptr =3D pc; + + return 0; +} + +/* Implement the gdbarch_skip_prologue method. + + Find the end of function prologue. */ + +static CORE_ADDR +nds32_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + CORE_ADDR func_addr, func_end; + struct symtab_and_line sal =3D { 0 }; + LONGEST return_value; + const char *func_name; + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + const int search_limit =3D 128; + + /* See what the symbol table says */ + if (find_pc_partial_function (pc, &func_name, &func_addr, &func_end)) + { + sal =3D find_pc_line (func_addr, 0); + + if (sal.line !=3D 0 && sal.end <=3D func_end) + { + func_end =3D sal.end; + } + else + { + /* Either there's no line info, or the line after the prologue + is after the end of the function. In this case, there probably + isn't a prologue. */ + func_end =3D min (func_end, func_addr + search_limit); + } + } + else + func_end =3D pc + search_limit; + + /* If current instruction is not readable, just quit. */ + if (!safe_read_memory_integer (pc, 4, byte_order, &return_value)) + return pc; + + /* Find the end of prologue. */ + if (nds32_analyze_prologue (gdbarch, pc, func_end, &sal.end) < 0) + return pc; + + return sal.end; +} + +struct nds32_unwind_cache +{ + /* The previous frame's inner most stack address. + Used as this frame ID's stack_addr. */ + CORE_ADDR prev_sp; + + /* The frame's base, optionally used by the high-level debug info. */ + CORE_ADDR base; + int size; + + /* How far the SP and FP have been offset from the start of + the stack frame (as defined by the previous frame's stack + pointer). */ + LONGEST sp_offset; + LONGEST fp_offset; + int use_frame; + + /* Table indicating the location of each and every register. */ + struct trad_frame_saved_reg *saved_regs; +}; + +static struct nds32_unwind_cache * +nds32_alloc_frame_cache (struct frame_info *this_frame) +{ + struct nds32_unwind_cache *cache; + cache =3D FRAME_OBSTACK_ZALLOC (struct nds32_unwind_cache); + + cache->saved_regs =3D trad_frame_alloc_saved_regs (this_frame); + cache->size =3D 0; + cache->sp_offset =3D 0; + cache->fp_offset =3D 0; + cache->use_frame =3D 0; + cache->base =3D 0; + + return cache; +} + +/* Implement the gdbarch_in_function_epilogue_p method. */ + +static int +nds32_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + uint32_t insn; + int r =3D 0; + + insn =3D read_memory_unsigned_integer (addr, 4, BFD_ENDIAN_BIG); + if ((insn & 0x80000000) =3D=3D 0) + { + /* 32-bit instruction */ + + /* ret */ + if (insn =3D=3D N32_JREG (JR, 0, REG_LP, 0, 1)) + r =3D 1; + /* iret */ + else if (insn =3D=3D N32_TYPE0 (MISC, N32_MISC_IRET)) + r =3D 2; + } + else + { + if (insn =3D=3D N16_TYPE5 (RET5, REG_LP)) + r =3D 3; + } + return r > 0; +} + +/* Put here the code to store, into fi->saved_regs, the addresses of + the saved registers of frame described by FRAME_INFO. This + includes special registers such as pc and fp saved in special ways + in the stack frame. sp is even more special: the address we return + for it IS the sp for the next frame. */ + +static struct nds32_unwind_cache * +nds32_frame_unwind_cache (struct frame_info *this_frame, + void **this_prologue_cache) +{ + CORE_ADDR pc, scan_limit; + ULONGEST prev_sp; + ULONGEST next_base; + ULONGEST fp_base; + int i; + int insn; + struct nds32_unwind_cache *info; + struct gdbarch *gdbarch =3D get_frame_arch (this_frame); + + if ((*this_prologue_cache)) + return (*this_prologue_cache); + + info =3D nds32_alloc_frame_cache (this_frame); + + info->base =3D get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM); + (*this_prologue_cache) =3D info; + + if (info->base =3D=3D 0) + return info; + + pc =3D get_frame_func (this_frame); + scan_limit =3D get_frame_pc (this_frame); + + for (; pc > 0 && pc < scan_limit; ) + { + insn =3D read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG); + + if ((insn & 0x80000000) =3D=3D 0) + { + /* 32-bit instruction */ + + pc +=3D 4; + if (insn =3D=3D N32_ALU1 (ADD, REG_GP, REG_TA, REG_GP)) + { + /* add $gp, $ta, $gp */ + continue; + } + if (N32_OP6 (insn) =3D=3D N32_OP6_ADDI) + { + int rt =3D N32_RT5 (insn); + int ra =3D N32_RA5 (insn); + int imm15s =3D N32_IMM15S (insn); + + if (rt =3D=3D ra && rt =3D=3D NDS32_SP_REGNUM) + { + info->sp_offset +=3D imm15s; + continue; + } + else if (rt =3D=3D NDS32_FP_REGNUM && ra =3D=3D NDS32_SP_REGNUM) + { + info->fp_offset =3D info->sp_offset + imm15s; + info->use_frame =3D 1; + continue; + } + else if (rt =3D=3D ra) + /* Prevent stop analyzing form iframe. */ + continue; + } + + if (insn =3D=3D N32_ALU2 (MFUSR, REG_TA, 31, 0)) + { + /* mfusr $ta, PC ; group=3D0, sub=3D0x20=3Dmfusr */ + continue; + } + if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (MOVI, REG_TA, 0)) + { + /* movi $ta, imm20s */ + continue; + } + if (CHOP_BITS (insn, 20) =3D=3D N32_TYPE1 (SETHI, REG_GP, 0)) + { + /* sethi $gp, imm20 */ + continue; + } + if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (ORI, REG_GP, REG_GP, 0)) + { + /* ori $gp, $gp, imm15 */ + continue; + } + if (N32_OP6 (insn) =3D=3D N32_OP6_LSMW && (insn & __BIT (5))) + { + /* smwa?.(a|b)(d|i)m? rb,[ra],re,enable4 */ + + int rb, re, ra, enable4, i; + int aligned; + int m =3D 0; + int di; /* dec=3D-1 or inc=3D1 */ + int rn; /* number of registers. */ + char enb4map[2][4] =3D { + {0, 1, 2, 3} /* smw */, + {3, 1, 2, 0} /* smwa */ }; + /* `base' is the highest/last address for access memory. + e.g., [ lp ] ___ base shoule be here. + [ fp ] + [ r6 ] */ + LONGEST base =3D ~1 + 1; + + rb =3D N32_RT5 (insn); + ra =3D N32_RA5 (insn); + re =3D N32_RB5 (insn); + enable4 =3D (insn >> 6) & 0x0F; + aligned =3D (insn & 3) ? 1 : 0; + di =3D (insn & (1 << 3)) ? -1 : 1; + + rn =3D 0; + rn +=3D (enable4 & 0x1) ? 1 : 0; + rn +=3D (enable4 & 0x2) ? 1 : 0; + rn +=3D (enable4 & 0x4) ? 1 : 0; + rn +=3D (enable4 & 0x8) ? 1 : 0; + if (rb < NDS32_FP_REGNUM && re < NDS32_FP_REGNUM) + { + /* reg-list should not include fp,gp,lp,sp + ie, the rb=3D=3Dre=3D=3Dsp case, anyway... */ + rn +=3D (re - rb) + 1; + } + + /* Let's consider how Ra should update. */ + if (insn & (1 << 0x2)) /* m-bit is set */ + { + m =3D rn * 4; /* 4*TNReg */ + } + else + m =3D 0; /* don't update Ra */ + + switch (ra) + { + case NDS32_FP_REGNUM: + base =3D info->fp_offset; + info->fp_offset +=3D m * di; + break; + case NDS32_SP_REGNUM: + base =3D info->sp_offset; + info->sp_offset +=3D m * di; + break; + default: + /* sorry, only ra=3D=3Dsp || ra=3D=3Dfp is handled */ + break; + } + if (base =3D=3D ~1 + 1) + break; /* skip */ + + if (insn & (1 << 0x4)) /* b:0, a:1 */ + base +=3D 4 * di; /* a: use Ra+4 (for i), + or Ra-4 (for d) */ + /* else base =3D base; b use Ra */ + + /* Cole 3th Nov. 2010 + We should consider both increasing and decreasing case. + + Either case stores registers in the same order. + To simplify the code (yes, the loops), + I used the same pushing order, but from different side. */ + + if (di =3D=3D 1) /* Increasing. */ + base +=3D (rn * 4 - 4); + /* else, in des case, we already are on the top */ + + for (i =3D 0; i < 4; i++) + { + if (enable4 & (1 << enb4map[aligned][i])) + { + info->saved_regs[NDS32_SP_REGNUM - + (enb4map[aligned][i])].addr =3D base; + base -=3D 4; + } + } + + /* Skip re =3D=3D rb =3D=3D sp > fp. */ + for (i =3D re; i >=3D rb && rb < NDS32_FP_REGNUM; i--) + { + info->saved_regs[i].addr =3D base; + base -=3D 4; + } + + continue; + } + /* swi $lp, [$sp + (imm15s << 2)] */ + /* We must check if $rt is $lp to determine it is + in prologue or not. */ + if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI, REG_LP, REG_FP, 0)) + { + int imm15s; + + /* swi $lp, [$sp + (imm15s<<2)] */ + imm15s =3D N32_IMM15S (insn); + info->saved_regs[NDS32_LP_REGNUM].addr =3D info->sp_offset + + (imm15s << 2); + continue; + } + /* swi.bi $rt, [$sp], (imm15s << 2) */ + if (CHOP_BITS (insn, 15) =3D=3D N32_TYPE2 (SWI_BI, REG_LP, REG_FP, 0)) + { + unsigned int rt5 =3D 0; + unsigned int ra5 =3D 0; + int imm15s =3D 0; + rt5 =3D N32_RT5 (insn); + ra5 =3D N32_RA5 (insn); + imm15s =3D N32_IMM15S (insn); + + if (ra5 =3D=3D NDS32_SP_REGNUM) + { + info->saved_regs[rt5].addr =3D info->sp_offset; + info->sp_offset +=3D (imm15s << 2); + } + else if (ra5 =3D=3D NDS32_FP_REGNUM) + { + info->saved_regs[rt5].addr =3D info->fp_offset; + info->fp_offset +=3D (imm15s << 2); + } + continue; + } + + if (N32_OP6 (insn) =3D=3D N32_OP6_COP && N32_COP_CP (insn) =3D=3D 0 + && (N32_COP_SUB (insn) =3D=3D N32_FPU_FSS + || N32_COP_SUB (insn) =3D=3D N32_FPU_FSD) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* CP shoud be CP0 */ + /* fs[sd][.bi] $fst, [$sp + ($r0 << sv)] */ + continue; + } + + /* fssi $fst, [$ra + (imm12s << 2)] + fssi.bi $fst, [$ra], (imm12s << 2) + fsdi $fdt, [$ra + (imm12s << 2)] + fsdi.bi $fdt, [$ra], (imm12s << 2) */ + if ((N32_OP6 (insn) =3D=3D N32_OP6_SWC || N32_OP6 (insn) =3D=3D N32_OP6= _SDC) + && (N32_RA5 (insn) =3D=3D REG_SP || N32_RA5 (insn) =3D=3D REG_FP)) + { + /* fssi and fsdi have the same form. */ + /* Only .bi form should be handled to adjust reg. */ + unsigned int ra5 =3D 0; + unsigned int fs5 =3D 0; + int imm12s =3D 0; + + fs5 =3D N32_RT5 (insn); + ra5 =3D N32_RA5 (insn); + imm12s =3D N32_IMM12S (insn); + + if (imm12s & 0x800) + imm12s =3D (imm12s - (0x800 << 1)); + + switch (ra5) + { + case NDS32_FP_REGNUM: + info->fp_offset +=3D (imm12s << 2); + break; + case NDS32_SP_REGNUM: + info->sp_offset +=3D (imm12s << 2); + break; + } + + continue; + } + + /* TODO: Handle mfsr and addi for interrupt handlers. */ + break; + } + else + { + /* 16-bit instruction */ + pc +=3D 2; + insn >>=3D 16; + + /* 1. If the instruction is j/b, then we stop + i.e., OP starts with 10, and beqzs8, bnezs8. + 2. If the operations will change sp/fp or based on sp/fp, + then we are in the prologue. + 3. If we don't know what's it, then stop. */ + + if (__GF (insn, 13, 2) =3D=3D 2) + { + /* These are all branch instructions. */ + pc -=3D 2; + break; + } + else if (__GF (insn, 9, 6) =3D=3D 0x34) + { + /* beqzs8, bnezs8 */ + pc -=3D 2; + break; + } + + if (CHOP_BITS (insn, 10) =3D=3D N16_TYPE10 (ADDI10S, 0)) + { + /* addi10s */ + info->sp_offset +=3D N16_IMM10S (insn); + continue; + } + + if (__GF (insn, 7, 8) =3D=3D N16_T25_PUSH25) + { + /* push25 */ + int imm8u =3D (insn & 0x1f) << 3; + int re =3D ((insn & 0x60) >> 5) & 0x3; + int res[] =3D {6, 8, 10, 14}; + int m[] =3D {4, 6, 8, 12}; + LONGEST base =3D info->sp_offset - 4; + + /* Operation 1 - smw.adm R6, [sp], Re, #0xe */ + info->saved_regs[NDS32_LP_REGNUM].addr =3D info->sp_offset - 0x4; + info->saved_regs[NDS32_GP_REGNUM].addr =3D info->sp_offset - 0x8; + info->saved_regs[NDS32_FP_REGNUM].addr =3D info->sp_offset - 0xC; + info->sp_offset -=3D m[re] * 4; + + switch (re) + { + case 3: + info->saved_regs[NDS32_R0_REGNUM + 14].addr =3D info->sp_offset + 0x= 20; + info->saved_regs[NDS32_R0_REGNUM + 13].addr =3D info->sp_offset + 0x= 1C; + info->saved_regs[NDS32_R0_REGNUM + 12].addr =3D info->sp_offset + 0x= 18; + info->saved_regs[NDS32_R0_REGNUM + 11].addr =3D info->sp_offset + 0x= 14; + case 2: + info->saved_regs[NDS32_R0_REGNUM + 10].addr =3D info->sp_offset + 0x= 10; + info->saved_regs[NDS32_R0_REGNUM + 9].addr =3D info->sp_offset + 0xC; + case 1: + info->saved_regs[NDS32_R0_REGNUM + 8].addr =3D info->sp_offset + 0x8; + info->saved_regs[NDS32_R0_REGNUM + 7].addr =3D info->sp_offset + 0x4; + case 0: + info->saved_regs[NDS32_R0_REGNUM + 6].addr =3D info->sp_offset; + } + + /* Operation 2 - sp =3D sp - imm5u<<3 */ + info->sp_offset -=3D imm8u; + + /* Operation 3 - if (Re >=3D 1) R8 =3D concat (PC(31,2), 2`b0) */ + continue; + } + + /* mov55 fp, sp */ + if (insn =3D=3D N16_TYPE55 (MOV55, REG_FP, REG_SP)) + { + info->fp_offset =3D info->sp_offset; + info->use_frame =3D 1; + continue; + } + /* swi450 */ + switch (insn & ~__MF (-1, 5, 4)) + { + case N16_TYPE45 (SWI450, 0, REG_SP): + case N16_TYPE45 (SWI450, 0, REG_FP): + break; + } + /* swi37 - implied fp */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37 + && (insn & __BIT (7))) + continue; + + /* swi37sp - implied */ + if (__GF (insn, 11, 4) =3D=3D N16_T37_XWI37SP + && (insn & __BIT (7))) + continue; + + break; + } + } + + info->size =3D -info->sp_offset; + /* Compute the previous frame's stack pointer (which is also the + frame's ID's stack address), and this frame's base pointer. + + Assume that the FP is this frame's SP but with that pushed + stack space added back. */ + next_base =3D get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM); + prev_sp =3D next_base + info->size; + fp_base =3D get_frame_register_unsigned (this_frame, NDS32_FP_REGNUM); + if (info->use_frame && fp_base > 0) + { + /* Try to use FP if possible. */ + prev_sp =3D fp_base - info->fp_offset; + } + + /* Convert that SP/BASE into real addresses. */ + info->prev_sp =3D prev_sp; + info->base =3D next_base; + + /* Adjust all the saved registers so that they contain addresses and + not offsets. */ + for (i =3D 0; i < gdbarch_num_regs (gdbarch) - 1; i++) + { + if (trad_frame_addr_p (info->saved_regs, i)) + { + info->saved_regs[i].addr =3D info->prev_sp + info->saved_regs[i].addr; + } + } + + /* The previous frame's SP needed to be computed. + Save the computed value. */ + trad_frame_set_value (info->saved_regs, NDS32_SP_REGNUM, prev_sp); + + return info; +} + +/* Implement the gdbarch_skip_permanent_breakpoint method. */ + +static void +nds32_skip_permanent_breakpoint (struct regcache *regcache) +{ + int insn; + CORE_ADDR current_pc =3D regcache_read_pc (regcache); + + /* On nds32, breakpoint may be BREAK or BREAK16. */ + insn =3D read_memory_unsigned_integer (current_pc, 4, BFD_ENDIAN_BIG); + + /* FIXME: Review this code. */ + if (N32_OP6 (insn) =3D=3D N32_OP6_MISC && N32_SUB5 (insn) =3D=3D N32_MIS= C_BREAK) + current_pc +=3D 4; + else if (__GF (insn, 9, 6) =3D=3D 35 && N16_IMM9U (insn) < 32) + current_pc +=3D 2; + else + return; + + regcache_write_pc (regcache, current_pc); +} + +/* Implement the gdbarch_read_pc method. */ + +static CORE_ADDR +nds32_read_pc (struct regcache *regcache) +{ + ULONGEST pc; + regcache_cooked_read_unsigned (regcache, NDS32_PC_REGNUM, &pc); + return pc; +} + +/* Implement the gdbarch_write_pc method. */ + +static void +nds32_write_pc (struct regcache *regcache, CORE_ADDR val) +{ + regcache_cooked_write_unsigned (regcache, NDS32_PC_REGNUM, val); +} + +/* Implement the gdbarch_unwind_pc method. */ + +static CORE_ADDR +nds32_unwind_pc (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + /* This snippet code is a mess. + + In most case, LP is the actually register being saved. + Hence when unwinding pc for backtrace, LP should be the one. + That is, for frames (level > 0), unwinding the PC means + unwinding LP from the this_frame. + + However, for a top frame (level=3D=3D0), unwinding PC means + the current program counter (PC). + Besides, for dummy frame, PC stored in dummy_frame is the one + we want. + + We have to have these cases to make backtrace work properly. */ + + CORE_ADDR pc; + pc =3D frame_unwind_register_unsigned (this_frame, NDS32_PC_REGNUM); + return pc; +} + +/* Implement the gdbarch_unwind_sp method. */ + +static CORE_ADDR +nds32_unwind_sp (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + return frame_unwind_register_unsigned (this_frame, NDS32_SP_REGNUM); +} + +/* If these is exactly one float point type field in the struct, + the alignment of the struct is the size of the float pointer type. */ + +static int +nds32_float_in_struct (struct type *type) +{ + struct type *actual_type; + + type =3D check_typedef (type); + if (TYPE_CODE (type) !=3D TYPE_CODE_STRUCT || TYPE_NFIELDS (type) !=3D 1) + return 0; + + actual_type =3D check_typedef (TYPE_FIELD_TYPE (type, 0)); + if (TYPE_CODE (actual_type) =3D=3D TYPE_CODE_FLT) + { + gdb_assert (TYPE_LENGTH (type) =3D=3D 8 || TYPE_LENGTH (type) =3D=3D= 4); + return TYPE_LENGTH (type); + } + return 0; +} + +/* Get the alignment of the type. + + The alignment requirement of a structure is the largest alignment + requirement of its member, so we should traverse every member to + find the largest alignment. + + For example, + struct { int a; int b; char c } is 4-byte aligned, + and + struct {long long a; char c} is 8-byte aligned. */ + +static int +nds32_type_align (struct type *type) +{ + int align =3D 0; /* Current max alignment. */ + int i; + + gdb_assert (type !=3D NULL); + if (type =3D=3D NULL) + return 0; + + if (type->main_type->nfields =3D=3D 0) + return type->length; + + switch (TYPE_CODE (type)) + { + case TYPE_CODE_ARRAY: + return nds32_type_align (TYPE_TARGET_TYPE (type)); + case TYPE_CODE_ENUM: + return TYPE_LENGTH (type); + } + + /* For structs with only one float/double are treated as float/double. = */ + align =3D nds32_float_in_struct (type); + if (align) + return align; + + for (i =3D 0; i < TYPE_NFIELDS (type); i++) + { + int r =3D nds32_type_align (TYPE_FIELD_TYPE (type, i)); + + if (r > align) + align =3D r; + } + + return align; +} + +/* Implement the gdbarch_push_dummy_call method. */ + +static CORE_ADDR +nds32_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) +{ + const int REND =3D 6; /* Max arguments number. */ + int goff =3D 0; /* Current gpr for argument. */ + int foff =3D 0; /* Currnet gpr for argument. */ + int soff =3D 0; /* Current stack offset. */ + int i; + struct type *type; + enum type_code typecode; + CORE_ADDR regval; + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + int use_spill; + int use_fpr; + int fs0_regnum =3D -1, fd0_regnum =3D -1; + + switch (tdep->nds32_abi) + { + case NDS32_ABI_V2: + case NDS32_ABI_V2FP: + use_spill =3D FALSE; + break; + default: + use_spill =3D TRUE; + break; + } + + /* Use FP registers for calling iff when ABI=3D=3DV2FP. */ + use_fpr =3D (tdep->nds32_abi =3D=3D NDS32_ABI_V2FP); + if (use_fpr) + { + fs0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fs0", strlen ("fs0")); + fd0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fd0", strlen ("fd0")); + } + + /* Set the return address. For the nds32, the return breakpoint is + always at BP_ADDR. */ + regcache_cooked_write_unsigned (regcache, NDS32_LP_REGNUM, bp_addr); + + /* If STRUCT_RETURN is true, then the struct return address (in + STRUCT_ADDR) will consume the first argument-passing register. + Both adjust the register count and store that value. */ + if (struct_return) + { + regcache_cooked_write_unsigned (regcache, NDS32_R0_REGNUM, struct_ad= dr); + goff++; + } + + /* Now make sure there's space on the stack */ + for (i =3D 0; i < nargs; i++) + { + struct type *type =3D value_type (args[i]); + int align =3D nds32_type_align (type); + + gdb_assert (align !=3D 0); + sp -=3D TYPE_LENGTH (type); + if (align) + { + /* FIXME: Handle empty structure? */ + sp &=3D ~(align - 1); + } + } + + /* Stack must be 8-byte aligned. */ + sp =3D sp & ~7; + + soff =3D 0; + for (i =3D 0; i < nargs; i++) + { + const gdb_byte *val; + int align, len; + + type =3D value_type (args[i]); + typecode =3D TYPE_CODE (type); + align =3D nds32_float_in_struct (type); + if (align) + typecode =3D TYPE_CODE_FLT; + else + align =3D nds32_type_align (type); + len =3D TYPE_LENGTH (type); + + /* TODO: handle variables-size argument and variable-length arguments + + COLE, GDB cannot know whether a type is variable-sized, + so we don't know whether push it as reference or value. */ + + val =3D value_contents (args[i]); + + /* Once we start using stack, all arguments should go to stack + When use_fpr, all flt must go to fs/fd; otherwise go to stack. */ + if (use_fpr && typecode =3D=3D TYPE_CODE_FLT) + { + /* Adjust alignment. */ + foff =3D (foff + ((align - 1) >> 2)) & ~((align - 1) >> 2); + + if (foff < REND && !soff) + { + if (use_fpr && fs0_regnum =3D=3D -1) + goto error_no_fpr; + + switch (len) + { + case 4: + regcache_cooked_write (regcache, fs0_regnum + foff, val); + foff++; + continue; + case 8: + regcache_cooked_write (regcache, fd0_regnum + foff / 2, val); + foff +=3D 2; + continue; + default: + /* Long double? */ + internal_error (__FILE__, __LINE__, + "Do not know how to handle %d-byte double.\n", + len); + break; + } + } + } + else if (!soff) + { + /* Adjust alignment, and only adjust one time for one argument. */ + goff =3D (goff + ((align - 1) >> 2)) & ~((align - 1) >> 2); + if (!use_spill && len > (REND - goff) * 4) + goff =3D REND; + } + + /* + When passing arguments, + + * A composite type not larger than 4 bytes is passed + in $rN. The format is as if the value is loaded with + load instruction of corresponding size. (i.g., LB, LH, LW) + + For example, + + r0 + 31 0 + little: [x x b a] + BIG: [x x a b] + + * Otherwise, a composite type is passed in consective registers. + The size is rounded up to the nearest multiple of 4. + The successive registers hold the parts of the argument as if + were loaded using lmw instructions. + + For example, + + r0 r1 + 31 0 31 0 + little: [d c b a] [x x x e] + BIG: [a b c d] [e x x x] + + + When push an argument in stack, + + * A composite type not larger than 4 bytes is copied + to memory at the next free space, in little-endian. + In big-endian, the last byte of the argument is aligned + at the next word address. For example, + + sp [ - ] [ b ] hi + [ - ] [ a ] + [ b ] [ - ] + [ a ] [ - ] lo + little BIG + */ + + if (len > 4) + len =3D (len + 0x3) & ~0x3; + + while (len > 0) + { + if (soff + || (typecode =3D=3D TYPE_CODE_FLT && use_fpr && foff =3D=3D REND) + || goff =3D=3D REND) + { + int rlen =3D (len > 4) ? 4 : len; + + if (byte_order =3D=3D BFD_ENDIAN_BIG) + write_memory (sp + soff + 4 - rlen, val, rlen); + else + write_memory (sp + soff, val, rlen); + soff +=3D 4; + } + else + { + regval =3D extract_unsigned_integer (val, (len > 4) ? 4 : len, + byte_order); + regcache_cooked_write_unsigned (regcache, + goff + NDS32_R0_REGNUM, regval); + goff++; + } + + len -=3D register_size (gdbarch, goff); + val +=3D register_size (gdbarch, goff); + } + } + + /* Finally, update the SP register. */ + regcache_cooked_write_unsigned (regcache, NDS32_SP_REGNUM, sp); + + return sp; + +error_no_fpr: + /* If use_fpr, but no fs reigster exists, then it is an error. */ + /* FIXME: Restore stack. */ + error (_("Fail to call. FS0-FS5 is required.")); +} + +/* Given a return value in `regbuf' with a type `valtype', + extract and copy its value into `valbuf'. */ + +static void +nds32_extract_return_value (struct type *type, struct regcache *regcache, + gdb_byte *readbuf) +{ + int len =3D TYPE_LENGTH (type); + int typecode =3D TYPE_CODE (type); + struct gdbarch *gdbarch =3D get_regcache_arch (regcache); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + int i; + int fs0_regnum, fd0_regnum; + int use_fpr; + + use_fpr =3D (tdep->nds32_abi =3D=3D NDS32_ABI_V2FP); + + /* TODO: one-float, one-double is special case in V2FP. + Passed in FS/FD */ + gdb_assert (TYPE_LENGTH (type) <=3D 8); + if (nds32_float_in_struct (type)) + typecode =3D TYPE_CODE_FLT; + + if (typecode =3D=3D TYPE_CODE_FLT && use_fpr) + { + fs0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fs0", strlen ("fs0")); + fd0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fd0", strlen ("fd0")); + + if (len =3D=3D 4) + regcache_cooked_read (regcache, fs0_regnum, readbuf); + else if (len =3D=3D 8) + regcache_cooked_read (regcache, fd0_regnum, readbuf); + else + internal_error (__FILE__, __LINE__, + _("Cannot extract return value of %d bytes " + "long floating point."), + len); + } + else + { + /* When returning result, + + * A composite type not larger than 4 bytes is returned + in $r0. The format is as if the result is loaded with + load instruction of corresponding size. (i.g., LB, LH, LW) + + For example, + + r0 + 31 0 + little: [x x b a] + BIG: [x x a b] + + * Otherwise, a composite type not larger than 8 bytes + is returned in $r0 and $r1. In little-endian, the first + word is loaded in $r0. In big-endian, the last word + is loaded in $r1. + + For example, + + r0 r1 + 31 0 31 0 + little: [d c b a] [x x x e] + BIG: [x x x a] [b c d e] + */ + + if (len <=3D 4) + { + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - len, len, + readbuf); + else + regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 0, len, + readbuf); + } + else if (len <=3D 8) + { + int partial =3D len - 4; + + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + { + regcache_raw_read_part (regcache, NDS32_R0_REGNUM, 4 - partial, + partial, readbuf); + regcache_raw_read (regcache, NDS32_R0_REGNUM + 1, + readbuf + partial); + + } + else + { + regcache_raw_read (regcache, NDS32_R0_REGNUM, readbuf); + regcache_raw_read_part (regcache, NDS32_R0_REGNUM + 1, 0, + partial, readbuf + 4); + } + } + else + internal_error (__FILE__, __LINE__, + _("Cannot extract return value of %d bytes long."), + len); + } +} + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. + Things always get returned in RET1_REGNUM, RET2_REGNUM. */ + +static void +nds32_store_return_value (struct type *type, struct regcache *regcache, + const gdb_byte *writebuf) +{ + int len =3D TYPE_LENGTH (type); + int typecode =3D TYPE_CODE (type); + struct gdbarch *gdbarch =3D get_regcache_arch (regcache); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + int i; + int fs0_regnum, fd0_regnum; + int use_fpr; + + use_fpr =3D (tdep->nds32_abi =3D=3D NDS32_ABI_V2FP); + + /* TODO: one-float, one-double is special case in V2FP. + Passed in FS/FD */ + gdb_assert (TYPE_LENGTH (type) <=3D 8); + if (nds32_float_in_struct (type)) + typecode =3D TYPE_CODE_FLT; + + if (typecode =3D=3D TYPE_CODE_FLT && use_fpr) + { + fs0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fs0", strlen ("fs0")); + fd0_regnum =3D user_reg_map_name_to_regnum (gdbarch, "fd0", strlen ("fd0")); + + if (len =3D=3D 4) + regcache_cooked_write (regcache, fs0_regnum, writebuf); + else if (len =3D=3D 8) + regcache_cooked_write (regcache, fd0_regnum, writebuf); + else + internal_error (__FILE__, __LINE__, + _("Cannot store return value of %d bytes long " + "floating point."), + len); + } + else + { + if (len <=3D 4) + { + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - len, len, + writebuf); + else + regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 0, len, + writebuf); + } + else if (len <=3D 8) + { + int partial =3D len - 4; + + if (gdbarch_byte_order (gdbarch) =3D=3D BFD_ENDIAN_BIG) + { + regcache_raw_write_part (regcache, NDS32_R0_REGNUM, 4 - partial, + partial, writebuf); + regcache_raw_write (regcache, NDS32_R0_REGNUM + 1, + writebuf + partial); + + } + else + { + regcache_raw_write (regcache, NDS32_R0_REGNUM, writebuf); + regcache_raw_write_part (regcache, NDS32_R0_REGNUM + 1, 0, + partial, writebuf + 4); + } + } + else + internal_error (__FILE__, __LINE__, + _("Cannot store return value of %d bytes long."), + len); + } +} + +/* Implement the gdbarch_return_value method. */ + +static enum return_value_convention +nds32_return_value (struct gdbarch *gdbarch, struct value *func_type, + struct type *type, struct regcache *regcache, + gdb_byte *readbuf, const gdb_byte *writebuf) +{ + if (TYPE_LENGTH (type) > 8) + { + return RETURN_VALUE_STRUCT_CONVENTION; + } + else + { + /* `readbuf' is used for 'call' to get the return value. + `writebuf' is used for 'return' to set the return value. */ + if (readbuf !=3D NULL) + nds32_extract_return_value (type, regcache, readbuf); + if (writebuf !=3D NULL) + nds32_store_return_value (type, regcache, writebuf); + return RETURN_VALUE_REGISTER_CONVENTION; + } +} + +/* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that + dummy frame. The frame ID's base needs to match the TOS value + saved by save_dummy_frame_tos(), and the PC match the dummy frame's + breakpoint. */ + +static struct frame_id +nds32_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) +{ + CORE_ADDR sp, pc; + + sp =3D get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM); + pc =3D get_frame_pc (this_frame); + return frame_id_build (sp, get_frame_pc (this_frame)); +} + +/* Given a GDB frame, determine the address of the calling function's + frame. This will be used to create a new GDB frame struct. */ + +static void +nds32_frame_this_id (struct frame_info *this_frame, + void **this_prologue_cache, struct frame_id *this_id) +{ + struct nds32_unwind_cache *info; + CORE_ADDR base; + CORE_ADDR func; + struct minimal_symbol *msym_stack; + struct frame_id id; + enum bfd_endian byte_order_for_code =3D BFD_ENDIAN_BIG; + + info =3D nds32_frame_unwind_cache (this_frame, this_prologue_cache); + + /* Get function entry address */ + func =3D get_frame_func (this_frame); + + /* Hopefully the prologue analysis either correctly determined the + frame's base (which is the SP from the previous frame), or set + that base to "NULL". */ + base =3D info->prev_sp; + if (base =3D=3D 0) + return; + + id =3D frame_id_build (base, func); + (*this_id) =3D id; +} + +/* Get the value of register REGNUM in previous frame. */ + +static struct value * +nds32_frame_prev_register (struct frame_info *this_frame, + void **this_prologue_cache, int regnum) +{ + struct nds32_unwind_cache *cache; + cache =3D nds32_frame_unwind_cache (this_frame, this_prologue_cache); + + if (regnum =3D=3D NDS32_PC_REGNUM) + { + CORE_ADDR lr; + struct frame_info *next_frame; + + lr =3D frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM); + return frame_unwind_got_constant (this_frame, regnum, lr); + } + + return trad_frame_get_prev_register (this_frame, cache->saved_regs, regn= um); +} + +/* The register in previous frame. For example, the previous PC is + current LP. */ + +static struct value * +nds32_dwarf2_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct gdbarch *gdbarch =3D get_frame_arch (this_frame); + CORE_ADDR lp; + + switch (regnum) + { + case NDS32_PC_REGNUM: + lp =3D frame_unwind_register_unsigned (this_frame, NDS32_LP_REGNUM); + return frame_unwind_got_constant (this_frame, regnum, lp); + default: + internal_error (__FILE__, __LINE__, + _("Unexpected register %d"), regnum); + } + + return NULL; +} + +/* Callback of dwarf2_frame_set_init_reg. */ + +static void +nds32_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) +{ + switch (regnum) + { + case NDS32_PC_REGNUM: + reg->how =3D DWARF2_FRAME_REG_FN; + reg->loc.fn =3D nds32_dwarf2_prev_register; + break; + case NDS32_SP_REGNUM: + reg->how =3D DWARF2_FRAME_REG_CFA; + break; + } +} + +/* Implement the gdbarch_get_longjmp_target method. */ + +static int +nds32_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc) +{ + gdb_byte buf[4]; + CORE_ADDR jmp_buf_p; + struct gdbarch *gdbarch =3D get_frame_arch (frame); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + jmp_buf_p =3D get_frame_register_unsigned (frame, 0); + + /* Key is in setjmp(): + lmw.bim r6, [r0], r14 + lmw.bim r16, [r0], r19, 0xf */ + + if (target_read_memory (jmp_buf_p + 15 * 4, buf, 4)) + return 0; + + *pc =3D extract_unsigned_integer (buf, 4, byte_order); + + return 1; +} + +static const struct frame_unwind nds32_frame_unwind =3D +{ + NORMAL_FRAME, + default_frame_unwind_stop_reason, + nds32_frame_this_id, + nds32_frame_prev_register, + NULL /* unwind_data */, + default_frame_sniffer +}; + +/* Signal trampolines. */ + +static struct nds32_unwind_cache * +nds32_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cac= he) +{ + struct nds32_unwind_cache *cache; + CORE_ADDR addr; + gdb_byte buf[4]; + struct gdbarch *gdbarch =3D get_frame_arch (this_frame); + struct gdbarch_tdep *tdep =3D gdbarch_tdep (gdbarch); + enum bfd_endian byte_order =3D gdbarch_byte_order (gdbarch); + + if (*this_cache) + return *this_cache; + + cache =3D nds32_alloc_frame_cache (this_frame); + + cache->base =3D get_frame_register_unsigned (this_frame, NDS32_SP_REGNUM= ); + + addr =3D tdep->sigcontext_addr (this_frame); + + if (tdep->sc_reg_offset) + { + int i; + + /* GPRs, PC and d[01](lo|hi) */ + gdb_assert (tdep->sc_num_regs <=3D 37); + + for (i =3D 0; i < tdep->sc_num_regs; i++) + if (tdep->sc_reg_offset[i] !=3D -1) + cache->saved_regs[i].addr =3D addr + tdep->sc_reg_offset[i]; + } + else + { + cache->saved_regs[NDS32_PC_REGNUM].addr =3D addr + tdep->sc_pc_offse= t; + cache->saved_regs[NDS32_LP_REGNUM].addr =3D addr + tdep->sc_lp_offse= t; + cache->saved_regs[NDS32_SP_REGNUM].addr =3D addr + tdep->sc_sp_offse= t; + cache->saved_regs[NDS32_FP_REGNUM].addr =3D addr + tdep->sc_fp_offse= t; + } + + *this_cache =3D cache; + return cache; +} + +static void +nds32_sigtramp_frame_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + struct nds32_unwind_cache *cache; + + cache =3D nds32_sigtramp_frame_cache (this_frame, this_cache); + + (*this_id) =3D frame_id_build (cache->base, get_frame_pc (this_frame)); +} + +static struct value * +nds32_sigtramp_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct nds32_unwind_cache *cache; + + /* Make sure we've initialized the cache. */ + cache =3D nds32_sigtramp_frame_cache (this_frame, this_cache); + + /* For signal frame, unwind PC for PC and LP for LP; + otherwise, we will fail to unwind a leaf-function. + This different from unwinding a normal-frame. */ + return trad_frame_get_prev_register (this_frame, cache->saved_regs, regn= um); +} + +static int +nds32_sigtramp_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + struct gdbarch_tdep *tdep =3D gdbarch_tdep (get_frame_arch (this_frame)); + + /* We shouldn't even bother if we don't have a sigcontext_addr + handler. */ + if (tdep->sigcontext_addr =3D=3D NULL) + return 0; + + if (tdep->sigtramp_p !=3D NULL) + { + if (tdep->sigtramp_p (this_frame)) + return 1; + } + +#if 0 + /* TODO: extend the sniffer as following if (tdep->sigtramp_start !=3D= 0) */ + { + CORE_ADDR pc =3D frame_pc_unwind (this_frame); + + gdb_assert (tdep->sigtramp_end !=3D 0); + if (pc >=3D tdep->sigtramp_start && pc < tdep->sigtramp_end) + return &nds32_sigtramp_frame_unwind; + } +#endif + return 0; +} + +static const struct frame_unwind nds32_sigtramp_frame_unwind =3D +{ + SIGTRAMP_FRAME, + default_frame_unwind_stop_reason, + nds32_sigtramp_frame_this_id, + nds32_sigtramp_frame_prev_register, + NULL /* unwind_data */, + nds32_sigtramp_frame_sniffer +}; + +static CORE_ADDR +nds32_frame_base_address (struct frame_info *this_frame, void **this_cache) +{ + struct nds32_unwind_cache *info; + + info =3D nds32_frame_unwind_cache (this_frame, this_cache); + + return info->base; +} + +static const struct frame_base nds32_frame_base =3D +{ + &nds32_frame_unwind, + nds32_frame_base_address, + nds32_frame_base_address, + nds32_frame_base_address +}; + +static void +nds32_simple_overlay_update (struct obj_section *osect) +{ + struct minimal_symbol *minsym =3D NULL; + + minsym =3D lookup_minimal_symbol (".nds32.fixed.size", NULL, NULL); + if (minsym !=3D NULL && osect !=3D NULL) + { + bfd *obfd =3D osect->objfile->obfd; + asection *bsect =3D osect->the_bfd_section; + if (bfd_section_vma (obfd, bsect) < SYMBOL_VALUE_ADDRESS (minsym)) + { + osect->ovly_mapped =3D 1; + return; + } + } + + simple_overlay_update (osect); +} + +static int +gdb_print_insn_nds32 (bfd_vma memaddr, disassemble_info *info) +{ + struct gdbarch *gdbarch =3D info->application_data; + struct obj_section * s =3D find_pc_section (memaddr); + struct cleanup *back_to; + + /* Reload symtab if abfd changed. + In case there are multiple ITB in different shared objects. */ + if (s =3D=3D NULL || info->section !=3D s->the_bfd_section) + { + xfree (info->symtab); + info->symtab =3D NULL; + info->symtab_size =3D 0; + } + + if (info->symtab =3D=3D NULL && s && s->the_bfd_section) + { + long storage =3D bfd_get_symtab_upper_bound (s->objfile->obfd); + + if (storage <=3D 0) + goto done; + + info->section =3D s->the_bfd_section; + info->symtab =3D xmalloc (storage); + info->symtab_size =3D + bfd_canonicalize_symtab (s->the_bfd_section->owner, info->symtab); + } + +done: + return print_insn_nds32 (memaddr, info); +} + +/* Callback for gdbarch_init. */ + +static struct gdbarch * +nds32_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) +{ + struct gdbarch *gdbarch; + struct gdbarch_tdep *tdep; + struct gdbarch_list *best_arch; + const struct target_desc *tdesc =3D NULL; + unsigned int nds32_abi =3D NDS32_ABI_AUTO; + struct tdesc_arch_data *tdesc_data =3D NULL; + unsigned int eflags =3D 0; + int i; + + /* Extract the elf_flags, if available. */ + if (info.abfd && bfd_get_flavour (info.abfd) =3D=3D bfd_target_elf_flavo= ur) + { + eflags =3D elf_elfheader (info.abfd)->e_flags; + nds32_abi =3D (eflags >> 4) & 0xF; + } + + /* Allocate space for the new architecture. */ + tdep =3D XCALLOC (1, struct gdbarch_tdep); + gdbarch =3D gdbarch_alloc (&info, tdep); + + if (tdesc_has_registers (info.target_desc)) + { + int valid_p; + int fpregs =3D -1; + static const char *const nds32_fp_names[] =3D { "r28", "fp", NULL }; + static const char *const nds32_lp_names[] =3D { "r30", "lp", NULL }; + static const char *const nds32_sp_names[] =3D { "r31", "sp", NULL }; + const struct tdesc_feature *feature; + + /* Validate and initialize target-description here. */ + tdesc =3D info.target_desc; + tdesc_data =3D tdesc_data_alloc (); + + info.tdep_info =3D (void *) tdesc_data; + + feature =3D tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.core"); + if (!feature) + return 0; + + /* Validate for FP, LP, GP, PC. */ + valid_p =3D 1; + valid_p &=3D tdesc_numbered_register_choices (feature, tdesc_data, + NDS32_FP_REGNUM, + nds32_fp_names); + valid_p &=3D tdesc_numbered_register_choices (feature, tdesc_data, + NDS32_LP_REGNUM, + nds32_lp_names); + valid_p &=3D tdesc_numbered_register_choices (feature, tdesc_data, + NDS32_SP_REGNUM, + nds32_sp_names); + valid_p &=3D tdesc_numbered_register (feature, tdesc_data, + NDS32_PC_REGNUM, "pc"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + xfree (tdep); + gdbarch_free (gdbarch); + return NULL; + } + + /* Number R0-R27. */ + for (i =3D NDS32_R0_REGNUM; i < NDS32_FP_REGNUM; i++) + tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]); + + /* Number D0 and D1. */ + for (i =3D NDS32_D0LO_REGNUM; i <=3D NDS32_D1HI_REGNUM; i++) + tdesc_numbered_register (feature, tdesc_data, i, nds32_regnames[i]); + + /* Find register configuration of FPU. */ + feature =3D tdesc_find_feature (tdesc, "org.gnu.gdb.nds32.fpu"); + if (feature) + { + if (tdesc_unnumbered_register (feature, "fd31")) + fpregs =3D 3; + else if (tdesc_unnumbered_register (feature, "fd15")) + fpregs =3D 2; + else if (tdesc_unnumbered_register (feature, "fd7")) + fpregs =3D 1; + else if (tdesc_unnumbered_register (feature, "fd3")) + fpregs =3D 0; + } + tdep->nds32_fpregs =3D fpregs; + + /* If FS registers do not exist, make them pseudo registers + of FD registers. */ + if (fpregs !=3D -1 && tdesc_unnumbered_register (feature, "fs0") =3D= =3D 0) + { + int fsregs =3D (fpregs + 1) * 8; + + if (fsregs > 32) + fsregs =3D 32; + + set_gdbarch_num_pseudo_regs (gdbarch, fsregs); + set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_read); + set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_write= ); + set_tdesc_pseudo_register_name (gdbarch, nds32_register_name); + } + + set_gdbarch_num_regs (gdbarch, NDS32_NUM_REGS); + tdesc_use_registers (gdbarch, tdesc, tdesc_data); + } + else + { + /* Simulator or legacy target. */ + + /* Physical 32 FD registers. */ + set_gdbarch_num_regs (gdbarch, NDS32_SIM_NUM_REGS); + set_gdbarch_register_name (gdbarch, nds32_register_name); + + /* Pseudo 32 FS registers. */ + set_gdbarch_num_pseudo_regs (gdbarch, 32); + set_gdbarch_pseudo_register_read (gdbarch, nds32_pseudo_register_rea= d); + set_gdbarch_pseudo_register_write (gdbarch, nds32_pseudo_register_wr= ite); + } + + tdep->nds32_abi =3D nds32_abi; + tdep->eflags =3D eflags; + + /* Overwrite ABI if set explicitly. */ + if (nds32_config.use_abi !=3D NDS32_ABI_AUTO) + tdep->nds32_abi =3D nds32_config.use_abi; + + /* Set offsets for signal context. */ + tdep->sigtramp_p =3D NULL; + tdep->sigcontext_addr =3D NULL; + tdep->sc_pc_offset =3D -1; + tdep->sc_sp_offset =3D -1; + tdep->sc_fp_offset =3D -1; + + /* If there is already a candidate, use it. */ + for (best_arch =3D gdbarch_list_lookup_by_info (arches, &info); + best_arch !=3D NULL; + best_arch =3D gdbarch_list_lookup_by_info (best_arch->next, &info)) + { + struct gdbarch_tdep *idep =3D gdbarch_tdep (best_arch->gdbarch); + + if (nds32_abi !=3D idep->nds32_abi) + continue; + + /* Check FPU registers. */ + if (idep->nds32_fpregs !=3D tdep->nds32_fpregs) + continue; + + /* Found a match. */ + break; + } + + if (best_arch !=3D NULL) + { + xfree (tdep); + gdbarch_free (gdbarch); + return best_arch->gdbarch; + } + + nds32_add_reggroups (gdbarch); + + gdbarch_init_osabi (info, gdbarch); + + /* Override tdesc_register callbacks for system registers. */ + set_gdbarch_register_reggroup_p (gdbarch, nds32_register_reggroup_p); + set_gdbarch_register_type (gdbarch, nds32_register_type); + + set_gdbarch_sp_regnum (gdbarch, NDS32_SP_REGNUM); + set_gdbarch_pc_regnum (gdbarch, NDS32_PC_REGNUM); + set_gdbarch_read_pc (gdbarch, nds32_read_pc); + set_gdbarch_write_pc (gdbarch, nds32_write_pc); + set_gdbarch_unwind_sp (gdbarch, nds32_unwind_sp); + set_gdbarch_unwind_pc (gdbarch, nds32_unwind_pc); + set_gdbarch_in_function_epilogue_p (gdbarch, nds32_in_function_epilogue_= p); + set_gdbarch_dwarf2_reg_to_regnum (gdbarch, nds32_dwarf_dwarf2_reg_to_reg= num); + set_gdbarch_register_sim_regno (gdbarch, nds32_register_sim_regno); + set_gdbarch_push_dummy_call (gdbarch, nds32_push_dummy_call); + set_gdbarch_return_value (gdbarch, nds32_return_value); + set_gdbarch_skip_prologue (gdbarch, nds32_skip_prologue); + set_gdbarch_inner_than (gdbarch, core_addr_lessthan); + set_gdbarch_breakpoint_from_pc (gdbarch, nds32_breakpoint_from_pc); + set_gdbarch_remote_breakpoint_from_pc (gdbarch, nds32_remote_breakpoint_from_pc); + set_gdbarch_frame_align (gdbarch, nds32_frame_align); + frame_base_set_default (gdbarch, &nds32_frame_base); + + /* Methods for saving / extracting a dummy frame's ID. + The ID's stack address must match the SP value returned by + PUSH_DUMMY_CALL, and saved by generic_save_dummy_frame_tos. */ + set_gdbarch_dummy_id (gdbarch, nds32_dummy_id); + set_gdbarch_print_insn (gdbarch, gdb_print_insn_nds32); + set_gdbarch_skip_permanent_breakpoint (gdbarch, + nds32_skip_permanent_breakpoint); + /* Support simple overlay manager. */ + set_gdbarch_overlay_update (gdbarch, nds32_simple_overlay_update); + + /* Handle longjmp. */ + set_gdbarch_get_longjmp_target (gdbarch, nds32_get_longjmp_target); + + /* The order of appending is the order it check frame. */ + dwarf2_frame_set_init_reg (gdbarch, nds32_dwarf2_frame_init_reg); + if (nds32_config.use_cfi) + dwarf2_append_unwinders (gdbarch); + frame_unwind_append_unwinder (gdbarch, &nds32_sigtramp_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &nds32_frame_unwind); + + /* Add nds32 register aliases. */ + /* FIXME: This is a simple workaround to force user-reg being + initialized before gdbarch initialized. + Without this, calling user_reg_map_name_to_regnum () + will crash. */ + user_reg_add (gdbarch, "r0", nds32_value_of_reg, "r0"); + for (i =3D 0; i < ARRAY_SIZE (nds32_register_aliases); i++) + { + int regnum; + + regnum =3D user_reg_map_name_to_regnum + (gdbarch, nds32_register_aliases[i].name, -1); + + if (regnum =3D=3D -1) + continue; + + user_reg_add (gdbarch, nds32_register_aliases[i].alias, + nds32_value_of_reg, nds32_register_aliases[i].name); + } + + return gdbarch; +} + +/* Callback for "nds32 dump" command. + + Dump current register and stack for debug gdb. */ + +static void +nds32_dump_command (char *arg, int from_tty) +{ + ULONGEST val; + ULONGEST sp; + FILE *f_script; + char cmdline[512]; + int i; + + if (arg =3D=3D NULL) + { + printf_unfiltered (_("Missing filename argument.\n")); + return; + } + + regcache_raw_read_unsigned (get_current_regcache (), NDS32_SP_REGNUM, &s= p); + + sprintf (cmdline, "dump binary memory %s.stack 0x%lx 0x%lx", + arg, (long) sp, ((long) sp + 1024 - 1) & ~(1024 - 1)); + execute_command (cmdline, from_tty); + + sprintf (cmdline, "%s.gdbinit", arg); + f_script =3D fopen (cmdline, "w"); + if (f_script =3D=3D NULL) + { + printf_unfiltered (_("Fail to generate dump .gdbinit.")); + return ; + } + + /* Gather all user registers. */ + for (i =3D 0; i <=3D NDS32_D1HI_REGNUM; i++) + { + regcache_raw_read_unsigned (get_current_regcache (), i, &val); + fprintf (f_script, "set $%s =3D 0x%lx\n", nds32_regnames[i], (long) = val); + } + + fprintf (f_script, "restore %s.stack binary 0x%lx\n", arg, (long) sp); + fclose (f_script); +} + +static int +nds32_config_int (const char *str, int def) +{ + int val =3D def; + + if (getenv (str)) + val =3D atoi (getenv (str)); + if (val !=3D def) + printf ("%s=3D%d\n", str, val); + return val; +} + +static void +nds32_load_config (struct nds32_gdb_config *config) +{ + config->use_cfi =3D nds32_config_int ("USE_CFI", 1); + config->use_abi =3D nds32_config_int ("USE_ABI", NDS32_ABI_AUTO); +} + +/* Callback for "nds32" command. */ + +static void +nds32_command (char *arg, int from_tty) +{ + printf_unfiltered (_("\"nds32\" must be followed by arguments\n")); +} + +struct cmd_list_element *nds32_cmdlist; + +void +_initialize_nds32_tdep (void) +{ + /* Internal used config for testing. */ + nds32_load_config (&nds32_config); + + add_prefix_cmd ("nds32", no_class, nds32_command, + _("Various nds32-specific commands."), &nds32_cmdlist, + "nds32 ", 0, &cmdlist); + + add_cmd ("dump", class_files, nds32_dump_command, + _("dump stack and GPRs for debugging"), &nds32_cmdlist); + + nds32_init_remote_cmds (); + + /* Initialize gdbarch. */ + register_gdbarch_init (bfd_arch_nds32, nds32_gdbarch_init); + + /* Following are NDS32 specific commands. */ + + nds32_init_reggroups (); + + register_remote_support_xml ("nds32"); +} diff --git a/gdb/nds32-tdep.h b/gdb/nds32-tdep.h new file mode 100644 index 0000000..2a71a14 --- /dev/null +++ b/gdb/nds32-tdep.h @@ -0,0 +1,127 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#include "nds32-utils.h" + +#ifndef __NDS32_TDEP_H__ +#define __NDS32_TDEP_H__ + +/* Define numbers of registers we have in NDS32 arch. */ + +#define NDS32_NUM_PSEUDO_REGS (NDS32_NUM_FPR) + +/* NDS32 virtual registers layout for GDB. */ +enum nds32_regnum +{ + /* General purpose registers. */ + NDS32_R0_REGNUM =3D 0, + NDS32_R5_REGNUM =3D 5, + NDS32_TA_REGNUM =3D 15, /* Temp for assembler. */ + NDS32_FP_REGNUM =3D 28, /* Frame register. */ + NDS32_GP_REGNUM =3D 29, /* Global register. */ + NDS32_LP_REGNUM =3D 30, /* Link pointer. */ + NDS32_SP_REGNUM =3D 31, /* Address of stack top. */ + + /* Pseudo PC. */ + NDS32_PC_REGNUM =3D 32, + + /* D0/D1 User Registers. */ + NDS32_D0LO_REGNUM =3D 33, + NDS32_D0HI_REGNUM =3D 34, + NDS32_D1LO_REGNUM =3D 35, + NDS32_D1HI_REGNUM =3D 36, + + /* If target-description is not supported, only assume above + registers are supported. */ + NDS32_NUM_REGS, + + /* These are only used by simulator. */ + NDS32_SIM_FD0_REGNUM =3D NDS32_NUM_REGS, + NDS32_SIM_IFCLP_REGNUM =3D NDS32_SIM_FD0_REGNUM + 32, + NDS32_SIM_ITB_REGNUM, + NDS32_SIM_PSW_REGNUM, + + NDS32_SIM_NUM_REGS, +}; + +/* All the possible NDS32 ABIs. They must be consistent with elf/nds32.h.= */ +enum nds32_abi +{ + NDS32_ABI_V0 =3D 0, + NDS32_ABI_V1, + NDS32_ABI_V2, + NDS32_ABI_V2FP, + NDS32_ABI_AABI, + NDS32_ABI_END, + NDS32_ABI_BEGIN =3D NDS32_ABI_V0, + /* ABI flag is only 4-bits long. */ + NDS32_ABI_AUTO =3D 0xFFFFFFFF +}; + +/* ---------------------------------------------- + 31 28 27 8 7 4 3 0 + ---------------------------------------------- + | ARCH | CONFUGURAION FIELD | ABI | VERSION | + ---------------------------------------------- */ +struct htab; +struct gdbarch_tdep +{ + /* ABI version */ + enum nds32_abi nds32_abi; + int nds32_fpregs; + + unsigned int eflags; + + /* Detect sigtramp. */ + int (*sigtramp_p) (struct frame_info *); + + /* Get address of sigcontext for sigtramp. */ + CORE_ADDR (*sigcontext_addr) (struct frame_info *); + + /* Offset of saved PC in jmp_buf. */ + /* TODO: int jb_pc_offset; */ + + /* Offset of saved PC and SP in `struct sigcontext'. */ + int sc_pc_offset; + int sc_lp_offset; + int sc_sp_offset; + int sc_fp_offset; + + int *sc_reg_offset; + int sc_num_regs; + + struct htab *type_tab; +}; + +/* Hidden options. */ +struct nds32_gdb_config +{ + /* Use DWARF/CFI for stack frame unwinding. + This is much reliable than manual prologue analysis. + Default true. */ + int use_cfi; + + /* ABI for Inferior Call Setup. + Default AUTO by reading ABI in ELF header. */ + int use_abi; +}; + +extern struct cmd_list_element *nds32_cmdlist; +#endif diff --git a/gdb/nds32-utils.c b/gdb/nds32-utils.c new file mode 100644 index 0000000..27241e7 --- /dev/null +++ b/gdb/nds32-utils.c @@ -0,0 +1,247 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#include "defs.h" +#include "top.h" /* for source_script */ +#include "exceptions.h" /* for catch_command_errors */ +#include "ui-file.h" /* struct ui_file_buffer */ +#include "nds32-utils.h" +#include "gdbtypes.h" +#include "gdb_assert.h" +#include "floatformat.h" +#include "hashtab.h" +#include +#include + +/* Helpers for allocating types. */ + +/* Allocate a new type. + Use this instead of arch_composite_type () or arch_type () directly, + because it must be a 4-byte word, but we may not append all the fields. + If `opt' is USE_FLAGS, then a field for flags is appended. */ + +struct type * +nds32_init_type (struct gdbarch *gdbarch, char *name, enum type_option opt) +{ + struct type *type; + + gdb_assert (opt =3D=3D USE_FLAGS || opt =3D=3D NO_FLAGS); + + type =3D arch_type (gdbarch, TYPE_CODE_STRUCT, 4, name); + TYPE_TAG_NAME (type) =3D name; + INIT_CPLUS_SPECIFIC (type); + + if (opt =3D=3D USE_FLAGS) + { + int i; + struct type *flags_type =3D + arch_flags_type (TYPE_OWNER (type).gdbarch, "nds32_dummy_flags_type", + TYPE_LENGTH (type)); + append_composite_type_field_raw (type, "", flags_type); + + /* Hide all the flags from users, + only explicitly appened flags are showen to users. + For example, + {[ #1 #3 #16 #17 #18 ], INTL =3D Lv1, POM =3D Superuser} + We don't want users to see this, + INTL and POM should be hidden from users. */ + for (i =3D 0; i < TYPE_LENGTH (type) * TARGET_CHAR_BIT; i++) + append_flags_type_flag (flags_type, i, NULL); + } + + return type; +} + +/* Append a flags bit. */ + +void +nds32_append_flag (struct type *type, int bitpos, char *name) +{ + struct field *f; + int nfields; + + gdb_assert (TYPE_CODE (type) =3D=3D TYPE_CODE_STRUCT); + + nfields =3D TYPE_NFIELDS (type); + + if (nfields =3D=3D 0 + || TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) !=3D TYPE_CODE_FLAGS) + { + internal_error (__FILE__, __LINE__, + _("Pseudo field for flags must be the first one.")); + } + + /* Append flag in the first field. */ + append_flags_type_flag (TYPE_FIELD_TYPE (type, 0), bitpos, name); +} + +/* Append a bit-field. */ + +void +nds32_append_bitfield (struct type *type, struct type *field_type, + int bitpos_from, int bitpos_to, char *name) +{ + struct field *f; + + gdb_assert (TYPE_CODE (type) =3D=3D TYPE_CODE_STRUCT); + gdb_assert (bitpos_to >=3D bitpos_from); + gdb_assert (TYPE_NFIELDS (type) !=3D 0 || strcmp (name, "") !=3D 0); + + f =3D append_composite_type_field_raw (type, xstrdup (name), field_type); + SET_FIELD_BITPOS (f[0], bitpos_from); + FIELD_BITSIZE (f[0]) =3D bitpos_to - bitpos_from + 1; +} + +/* Allocate an enumeration type. The only reason to call this function + is that we want it to be UNSIGNED instead. This is only useful for + enum-type bit-field. */ + +struct type * +nds32_init_enum (struct gdbarch *gdbarch, char *name) +{ + struct type *type; + + type =3D arch_type (gdbarch, TYPE_CODE_ENUM, 4, name); + TYPE_UNSIGNED (type) =3D 1; + return type; +} + +void +nds32_append_enum (struct type *type, int enumval, char *name) +{ + struct field *f; + + gdb_assert (TYPE_CODE (type) =3D=3D TYPE_CODE_ENUM); + f =3D append_composite_type_field_raw (type, name, NULL); + SET_FIELD_ENUMVAL (f[0], enumval); +} +=0C +/* Helpers for type table. */ + +struct type_entry +{ + const char *name; + struct type *type; +}; + +/* Hash code function. Simply a wrapper for htab_hash_string. */ + +static hashval_t +type_hash_string (const PTR p) +{ + struct type_entry *e =3D (struct type_entry *) p; + + return htab_hash_string (e->name); +} + +/* Equal function for hash. Simply a wrapper for strcmp. */ + +static int +type_name_eq (const PTR p1, const PTR p2) +{ + struct type_entry *e1 =3D (struct type_entry *) p1; + struct type_entry *e2 =3D (struct type_entry *) p2; + + return strcmp (e1->name, e2->name) =3D=3D 0; +} + +/* Allocate a hash table for register/type pair. */ + +htab_t +nds32_alloc_type_tab (int size) +{ + return htab_create_alloc (size, type_hash_string, type_name_eq, + NULL /* htab_del */ , + xcalloc, xfree); +} + +/* Look up a register by name. */ + +struct type * +nds32_type_lookup (htab_t htab, const char *name) +{ + struct type_entry ent; + struct type_entry **pe; + + ent.name =3D name; + pe =3D (struct type_entry **) htab_find_slot (htab, &ent, NO_INSERT); + if (pe) + return (*pe)->type; + else + return NULL; +} + +/* Insert a type for a specific register name. */ + +void +nds32_type_insert (htab_t htab, const char *name, struct type *type) +{ + struct type_entry ent; + struct type_entry **pe; + + ent.name =3D name; + + pe =3D (struct type_entry **) htab_find_slot (htab, &ent, INSERT); + + if (*pe !=3D NULL) + return; + + *pe =3D xmalloc (sizeof (**pe)); + (*pe)->name =3D xstrdup (name); + (*pe)->type =3D type; +} +=0C +/* ui_file_put_method_ftype. + + This is used with mem_file_put to get the content of + the internal stream buffer. */ + +void +do_ui_file_put_memcpy (void *object, const char *buffer, long length_buffe= r) +{ + struct ui_file_buffer *ui_buf; + + ui_buf =3D (struct ui_file_buffer *) object; + if (ui_buf->buf_size < length_buffer) + { + if (length_buffer < 256 * 1024) + ui_buf->buf_size =3D length_buffer +=3D 1024; + else + ui_buf->buf_size =3D length_buffer * 2; + ui_buf->buf =3D xrealloc (ui_buf->buf, ui_buf->buf_size); + } + + memcpy (ui_buf->buf, buffer, length_buffer); +} + +void +ui_file_buffer_init (struct ui_file_buffer *ub, int size) +{ + ub->buf_size =3D size; + ub->buf =3D xmalloc (size); +} + +void +free_ui_file_buffer (void *ptr) +{ + struct ui_file_buffer *ui_buf =3D (struct ui_file_buffer *) ptr; + + xfree (ui_buf->buf); +} diff --git a/gdb/nds32-utils.h b/gdb/nds32-utils.h new file mode 100644 index 0000000..b1f9c2c --- /dev/null +++ b/gdb/nds32-utils.h @@ -0,0 +1,59 @@ +/* Common target dependent code for GDB on nds32 systems. + + Copyright (C) 2006-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + 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 . = */ + +#ifndef NDS32_UTILS_H +#define NDS32_UTILS_H + +void source_nds32script (void); + +/* Declarations for making arch-dependent types. */ +enum type_option +{ + NO_FLAGS =3D 0, + USE_FLAGS =3D 1, +}; +struct field *nds32_append_type_field (struct type *type); +struct type *nds32_init_type (struct gdbarch *gdbarch, char *name, + enum type_option opt); +void nds32_append_flag (struct type *type, int bitpos, char *name); +void nds32_append_bitfield (struct type *type, struct type *field_type, + int bitpos_from, int bitpos_to, char *name); +struct type *nds32_init_enum (struct gdbarch *gdbarch, char *name); +void nds32_append_enum (struct type *type, int bitpos, char *name); + +/* Helpers for type table. */ +htab_t nds32_alloc_type_tab (int size); +struct type *nds32_type_lookup (htab_t htab, const char *name); +void nds32_type_insert (htab_t htab, const char *name, struct type *type); + +/* UI buffer for output redirection. */ +struct ui_file_buffer +{ + unsigned char *buf; + long buf_size; +}; + +void do_ui_file_put_memcpy (void *object, const char *buffer, + long length_buffer); + +void ui_file_buffer_init (struct ui_file_buffer *ub, int size); + +void free_ui_file_buffer (void *ptr); +#endif diff --git a/gdb/regformats/nds32-freg0-linux.dat b/gdb/regformats/nds32-freg0-linux.dat new file mode 100644 index 0000000..49eafd3 --- /dev/null +++ b/gdb/regformats/nds32-freg0-linux.dat @@ -0,0 +1,47 @@ +# DO NOT EDIT: generated from nds32-freg0-linux.xml +name:nds32_freg0_linux +xmltarget:nds32-freg0-linux.xml +expedite:fp,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:r13 +32:r14 +32:r15 +32:r16 +32:r17 +32:r18 +32:r19 +32:r20 +32:r21 +32:r22 +32:r23 +32:r24 +32:r25 +32: +32: +32:fp +32:gp +32:lp +32:sp +32:pc +32:d0lo +32:d0hi +32:d1lo +32:d1hi +32:orig_r0 +32:fucpr +64:fd0 +64:fd1 +64:fd2 +64:fd3 diff --git a/gdb/regformats/nds32-freg1-linux.dat b/gdb/regformats/nds32-freg1-linux.dat new file mode 100644 index 0000000..312912e --- /dev/null +++ b/gdb/regformats/nds32-freg1-linux.dat @@ -0,0 +1,51 @@ +# DO NOT EDIT: generated from nds32-freg1-linux.xml +name:nds32_freg1_linux +xmltarget:nds32-freg1-linux.xml +expedite:fp,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:r13 +32:r14 +32:r15 +32:r16 +32:r17 +32:r18 +32:r19 +32:r20 +32:r21 +32:r22 +32:r23 +32:r24 +32:r25 +32: +32: +32:fp +32:gp +32:lp +32:sp +32:pc +32:d0lo +32:d0hi +32:d1lo +32:d1hi +32:orig_r0 +32:fucpr +64:fd0 +64:fd1 +64:fd2 +64:fd3 +64:fd4 +64:fd5 +64:fd6 +64:fd7 diff --git a/gdb/regformats/nds32-freg2-linux.dat b/gdb/regformats/nds32-freg2-linux.dat new file mode 100644 index 0000000..b281b50 --- /dev/null +++ b/gdb/regformats/nds32-freg2-linux.dat @@ -0,0 +1,59 @@ +# DO NOT EDIT: generated from nds32-freg2-linux.xml +name:nds32_freg2_linux +xmltarget:nds32-freg2-linux.xml +expedite:fp,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:r13 +32:r14 +32:r15 +32:r16 +32:r17 +32:r18 +32:r19 +32:r20 +32:r21 +32:r22 +32:r23 +32:r24 +32:r25 +32: +32: +32:fp +32:gp +32:lp +32:sp +32:pc +32:d0lo +32:d0hi +32:d1lo +32:d1hi +32:orig_r0 +32:fucpr +64:fd0 +64:fd1 +64:fd2 +64:fd3 +64:fd4 +64:fd5 +64:fd6 +64:fd7 +64:fd8 +64:fd9 +64:fd10 +64:fd11 +64:fd12 +64:fd13 +64:fd14 +64:fd15 diff --git a/gdb/regformats/nds32-freg3-linux.dat b/gdb/regformats/nds32-freg3-linux.dat new file mode 100644 index 0000000..f0c33f7 --- /dev/null +++ b/gdb/regformats/nds32-freg3-linux.dat @@ -0,0 +1,75 @@ +# DO NOT EDIT: generated from nds32-freg3-linux.xml +name:nds32_freg3_linux +xmltarget:nds32-freg3-linux.xml +expedite:fp,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:r13 +32:r14 +32:r15 +32:r16 +32:r17 +32:r18 +32:r19 +32:r20 +32:r21 +32:r22 +32:r23 +32:r24 +32:r25 +32: +32: +32:fp +32:gp +32:lp +32:sp +32:pc +32:d0lo +32:d0hi +32:d1lo +32:d1hi +32:orig_r0 +32:fucpr +64:fd0 +64:fd1 +64:fd2 +64:fd3 +64:fd4 +64:fd5 +64:fd6 +64:fd7 +64:fd8 +64:fd9 +64:fd10 +64:fd11 +64:fd12 +64:fd13 +64:fd14 +64:fd15 +64:fd16 +64:fd17 +64:fd18 +64:fd19 +64:fd20 +64:fd21 +64:fd22 +64:fd23 +64:fd24 +64:fd25 +64:fd26 +64:fd27 +64:fd28 +64:fd29 +64:fd30 +64:fd31 diff --git a/gdb/regformats/nds32-linux.dat b/gdb/regformats/nds32-linux.dat new file mode 100644 index 0000000..bd79c4d --- /dev/null +++ b/gdb/regformats/nds32-linux.dat @@ -0,0 +1,43 @@ +# DO NOT EDIT: generated from nds32-linux.xml +name:nds32_linux +xmltarget:nds32-linux.xml +expedite:fp,sp,pc +32:r0 +32:r1 +32:r2 +32:r3 +32:r4 +32:r5 +32:r6 +32:r7 +32:r8 +32:r9 +32:r10 +32:r11 +32:r12 +32:r13 +32:r14 +32:r15 +32:r16 +32:r17 +32:r18 +32:r19 +32:r20 +32:r21 +32:r22 +32:r23 +32:r24 +32:r25 +32: +32: +32:fp +32:gp +32:lp +32:sp +32:pc +32:d0lo +32:d0hi +32:d1lo +32:d1hi +32:orig_r0 +32:fucpr --=20 1.7.9.5