From patchwork Mon Dec 5 12:30:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alan Hayward X-Patchwork-Id: 18195 Received: (qmail 19736 invoked by alias); 5 Dec 2016 12:30:30 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 19613 invoked by uid 89); 5 Dec 2016 12:30:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-4.5 required=5.0 tests=BAYES_00, KAM_LOTSOFHASH, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=recorded, 68, 6, Override, 1758 X-HELO: foss.arm.com Received: from foss.arm.com (HELO foss.arm.com) (217.140.101.70) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 05 Dec 2016 12:30:10 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id C5D1615AB; Mon, 5 Dec 2016 04:30:08 -0800 (PST) Received: from [10.45.32.207] (e105284-mac.manchester.arm.com [10.45.32.207]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id EED193F445 for ; Mon, 5 Dec 2016 04:30:07 -0800 (PST) User-Agent: Microsoft-MacOutlook/14.7.0.161029 Date: Mon, 05 Dec 2016 12:30:02 +0000 Subject: [PATCH 7/8] AARCH64 SVE: Enable AArch64 SVE in gdb From: Alan Hayward To: Message-ID: Mime-version: 1.0 Content-type: text/plain; charset="UTF-8" Content-transfer-encoding: 7bit This is part of a series adding SVE support to gdb and gdbserver. This patch enables SVE support for the AArch64 version of gdb. On AArch64 the size of the V and P registers are dependant on the value of VG which is read and set using the ptrace command. The aarch64 version of the to_thread_architecture target_ops method ensures that the current VG value is read before finding the target descriptor. The initialize_tdesc_aarch64_sve () function (added in a previous patch) will initialise a target descriptor with an implied VG value of 1. Upon encountering a new value of VG, the target will intialise a new AArch64 SVE target descriptor, and then scale all the variable types and registers by the VG value. This will be stored in an array of all possible value of VG. Tested on x86 and AArch64. Ok to commit? Alan. { @@ -1304,6 +1304,31 @@ tdesc_create_reg (struct tdesc_feature *feature, const char *name, VEC_safe_push (tdesc_reg_p, feature->registers, reg); } +/* For a given feature, rescale the vector types and all vector registers. */ +void +tdesc_rescale_vector_types (struct tdesc_feature *feature, int scale) +{ + int ix; + struct tdesc_type *type; + + for (ix = 0; VEC_iterate (tdesc_type_p, feature->types, ix, type); ix++) + if (type->kind == TDESC_TYPE_VECTOR) + type->u.v.count *= scale; +} + +/* For a given feature, rescale the registers with the given type name. */ +void +tdesc_rescale_registers (struct tdesc_feature *feature, char *type_name, + int scale) +{ + int ix; + struct tdesc_reg *reg; + + for (ix = 0; VEC_iterate (tdesc_reg_p, feature->registers, ix, reg); ix++) + if (reg->tdesc_type && 0 == strcmp (reg->tdesc_type->name, type_name)) + reg->bitsize *= scale; +} + /* Subroutine of tdesc_free_feature to simplify it. Note: We do not want to free any referenced types here (e.g., types of fields of a struct). All types of a feature are recorded in diff --git a/gdb/aarch64-linux-nat.c b/gdb/aarch64-linux-nat.c index 5525b0dd46a1bb641f4b6003942613437202e785..97212864dcce84779b3a86355f0ac69c5 0e3b20e 100644 --- a/gdb/aarch64-linux-nat.c +++ b/gdb/aarch64-linux-nat.c @@ -44,6 +44,7 @@ /* Defines ps_err_e, struct ps_prochandle. */ #include "gdb_proc_service.h" +#include "arch-utils.h" #ifndef TRAP_HWBKPT #define TRAP_HWBKPT 0x0004 @@ -191,6 +192,34 @@ struct aarch64_process_info static struct aarch64_process_info *aarch64_process_list = NULL; + +/* Read VG for the given tid using ptrace. If SVE is not supported then zero + is returned. */ + +static unsigned long +aarch64_read_vg (int tid) +{ + int ret; + struct iovec iovec; + struct user_sve_header header; + + iovec.iov_len = sizeof (header); + iovec.iov_base = &header; + + /* Ptrace gives the vector length in bytes. Convert it to VG - which is the + number of 64bit chunks. We use VG because that is the value that appears + as a DWARF register. */ + + ret = ptrace (PTRACE_GETREGSET, tid, NT_ARM_SVE, &iovec); + if (ret >= 0) + { + gdb_assert (sve_vl_valid (header.vl)); + return sve_vg_from_vl (header.vl); + } + /* SVE is not supported. */ + return 0; +} + /* Find process data for process PID. */ static struct aarch64_process_info * @@ -900,7 +929,7 @@ aarch64_linux_read_description (struct target_ops *ops) if (ret == 0) return tdesc_arm_with_neon; else - return tdesc_aarch64; + return aarch64_get_tdesc (aarch64_read_vg (tid)); } /* Convert a native/host siginfo object, into/from the siginfo in the @@ -1179,6 +1208,20 @@ aarch64_linux_can_do_single_step (struct target_ops *target) return 1; } +/* Implement the "to_thread_architecture" target_ops method. */ + +static struct gdbarch * +aarch64_thread_architecture (struct target_ops *ops, ptid_t ptid) +{ + long vg = aarch64_read_vg (ptid_get_lwp (ptid)); + struct gdbarch_info info; + + gdbarch_info_init (&info); + info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu); + info.tdep_info = &vg; + return gdbarch_find_by_info (info); +} + /* Define AArch64 maintenance commands. */ static void @@ -1231,6 +1274,7 @@ _initialize_aarch64_linux_nat (void) t->to_watchpoint_addr_within_range = aarch64_linux_watchpoint_addr_within_range; t->to_can_do_single_step = aarch64_linux_can_do_single_step; + t->to_thread_architecture = aarch64_thread_architecture; /* Override the GNU/Linux inferior startup hook. */ super_post_startup_inferior = t->to_post_startup_inferior; diff --git a/gdb/aarch64-tdep.h b/gdb/aarch64-tdep.h index 2eaf268e9ea2e1a7912c5778033d3ff01737a648..2c789e7aca1c3c4e3150c88d53aae5afb 41e2410 100644 --- a/gdb/aarch64-tdep.h +++ b/gdb/aarch64-tdep.h @@ -111,11 +111,14 @@ struct gdbarch_tdep /* syscall record. */ int (*aarch64_syscall_record) (struct regcache *regcache, unsigned long svc_number); + + /* For SVE targets, the VG value. */ + long vg; }; -#define AARCH64_TDEP_HAS_SVE(tdep) (0) +#define AARCH64_TDEP_HAS_SVE(tdep) (tdep->vg != 0) -extern struct target_desc *tdesc_aarch64; +struct target_desc *aarch64_get_tdesc (long vg); extern int aarch64_process_record (struct gdbarch *gdbarch, struct regcache *regcache, CORE_ADDR addr); diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index 9808997664597484d006d380e003841528512ca5..e1cdee9e35534e1910c31feca5208ff1c d5bc8b5 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -51,6 +51,7 @@ #include "record.h" #include "record-full.h" #include "features/aarch64.c" +#include "features/aarch64-sve.c" #include "arch/aarch64-insn.h" #include "opcode/aarch64.h" #include @@ -68,6 +69,12 @@ #define AARCH64_B0_REGNUM (AARCH64_H0_REGNUM + 32) #define AARCH64_SVE_V0_REGNUM (AARCH64_B0_REGNUM + 32) +/* Maximum supported VG value. Increase if required. */ +#define AARCH64_TDEP_MAX_SVE_VG 32 + +/* All possible aarch64 target descriptors. */ +struct target_desc *tdesc_aarch64_sve_list[AARCH64_TDEP_MAX_SVE_VG + 1]; + /* The standard register names, and all the valid aliases for them. */ static const struct { @@ -2783,6 +2790,42 @@ aarch64_target_get_tdep_info (void *registers) return NULL; } +/* Get the correct target description for the given VG value. + If VG is zero then it is assumed SVE is not supported. + (It is not possible to set VG to zero on an SVE system). */ +struct target_desc * +aarch64_get_tdesc (long vg) +{ + if (vg > AARCH64_TDEP_MAX_SVE_VG) + error (_("VG is %ld, maximum supported value is %d"), vg, + AARCH64_TDEP_MAX_SVE_VG); + struct target_desc *tdesc; + + if (vg == 0) + return tdesc_aarch64; + + tdesc = tdesc_aarch64_sve_list[vg]; + + if (tdesc == NULL) + { + struct tdesc_feature *feature; + + /* The target descriptor for the given VG value has not been accessed + yet. Allocate a new one and then update all the register sizes. */ + + initialize_tdesc_aarch64_sve (); + tdesc = tdesc_aarch64_sve; + + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve"); + tdesc_rescale_vector_types (feature, vg); + tdesc_rescale_registers (feature, "svev", vg); + tdesc_rescale_registers (feature, "svep", vg); + + tdesc_aarch64_sve_list[vg] = tdesc; + } + return tdesc; +} + /* Initialize the current architecture based on INFO. If possible, re-use an architecture from ARCHES, which is a list of architectures already created during this debugging session. @@ -2800,19 +2843,35 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) const struct target_desc *tdesc = info.target_desc; int i; int valid_p = 1; - const struct tdesc_feature *feature; + const struct tdesc_feature *feature_core; + const struct tdesc_feature *feature_fpu; + const struct tdesc_feature *feature_sve; int num_regs = 0; int num_pseudo_regs = 0; - - /* Ensure we always have a target descriptor. */ - if (!tdesc_has_registers (tdesc)) - tdesc = tdesc_aarch64; - + long vg = 0; + + if (info.tdep_info) + vg = *(long *)info.tdep_info; + else if (tdesc && tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve")) + /* The current target descriptor says we have SVE but we were not given a + VG value. Set VG to the minimum SVE supported value. */ + vg = 2; + + if (vg > AARCH64_TDEP_MAX_SVE_VG) + internal_error (__FILE__, __LINE__, _("VG out of bounds: %ld (max %d)"), + vg, AARCH64_TDEP_MAX_SVE_VG); + + /* Ensure we always have a target descriptor, and that it is for the current + VG value. */ + if (!tdesc_has_registers (tdesc) || vg > 0) + tdesc = aarch64_get_tdesc (vg); gdb_assert (tdesc); - feature = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.core"); + feature_core = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.core"); + feature_fpu = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu"); + feature_sve = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.sve"); - if (feature == NULL) + if (feature_core == NULL) return NULL; tdesc_data = tdesc_data_alloc (); @@ -2820,25 +2879,47 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) /* Validate the descriptor provides the mandatory core R registers and allocate their numbers. */ for (i = 0; i < ARRAY_SIZE (aarch64_r_register_names); i++) - valid_p &= - tdesc_numbered_register (feature, tdesc_data, AARCH64_X0_REGNUM + i, - aarch64_r_register_names[i]); + valid_p &= tdesc_numbered_register (feature_core, tdesc_data, + AARCH64_X0_REGNUM + i, + aarch64_r_register_names[i]); num_regs = AARCH64_X0_REGNUM + i; - /* Look for the V registers. */ - feature = tdesc_find_feature (tdesc, "org.gnu.gdb.aarch64.fpu"); - if (feature) + /* Add the V registers. */ + if (feature_fpu != NULL) { + gdb_assert (feature_sve == NULL); + gdb_assert (vg == 0); + /* Validate the descriptor provides the mandatory V registers - and allocate their numbers. */ + and allocate their numbers. */ for (i = 0; i < ARRAY_SIZE (aarch64_v_register_names); i++) - valid_p &= - tdesc_numbered_register (feature, tdesc_data, AARCH64_V0_REGNUM + i, - aarch64_v_register_names[i]); + valid_p &= tdesc_numbered_register (feature_fpu, tdesc_data, + AARCH64_V0_REGNUM + i, + aarch64_v_register_names[i]); num_regs = AARCH64_V0_REGNUM + i; + } + + /* Add the SVE registers. */ + if (feature_sve != NULL) + { + gdb_assert (feature_fpu == NULL); + gdb_assert (vg > 0); + + /* Validate the descriptor provides the mandatory sve registers + and allocate their numbers. */ + for (i = 0; i < ARRAY_SIZE (aarch64_sve_register_names); i++) + valid_p &= tdesc_numbered_register (feature_sve, tdesc_data, + AARCH64_SVE_Z0_REGNUM + i, + aarch64_sve_register_names[i]); + + num_regs = AARCH64_SVE_Z0_REGNUM + i; + num_pseudo_regs += 32; /* add the Vn register pseudos. */ + } + if (feature_fpu != NULL || feature_sve != NULL) + { num_pseudo_regs += 32; /* add the Qn scalar register pseudos */ num_pseudo_regs += 32; /* add the Dn scalar register pseudos */ num_pseudo_regs += 32; /* add the Sn scalar register pseudos */ @@ -2860,15 +2941,14 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) best_arch != NULL; best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info)) { - /* Found a match. */ - break; - } - - if (best_arch != NULL) - { - if (tdesc_data != NULL) - tdesc_data_cleanup (tdesc_data); - return best_arch->gdbarch; + tdep = gdbarch_tdep (best_arch->gdbarch); + if (tdep && tdep->vg == vg) + { + /* Found a match. */ + if (tdesc_data != NULL) + tdesc_data_cleanup (tdesc_data); + return best_arch->gdbarch; + } } tdep = XCNEW (struct gdbarch_tdep); @@ -2878,6 +2958,7 @@ aarch64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->lowest_pc = 0x20; tdep->jb_pc = -1; /* Longjump support not enabled by default. */ tdep->jb_elt_size = 8; + tdep->vg = vg; set_gdbarch_push_dummy_call (gdbarch, aarch64_push_dummy_call); set_gdbarch_frame_align (gdbarch, aarch64_frame_align); diff --git a/gdb/target-descriptions.h b/gdb/target-descriptions.h index ef97d1d5f76d80bad1a47c435fa1b7f3cb871d73..217293a4f4e29dccf191508efab1f6a43 9623aac 100644 --- a/gdb/target-descriptions.h +++ b/gdb/target-descriptions.h @@ -175,8 +175,8 @@ int tdesc_has_registers (const struct target_desc *); /* Return the feature with the given name, if present, or NULL if the named feature is not found. */ -const struct tdesc_feature *tdesc_find_feature (const struct target_desc *, - const char *name); +struct tdesc_feature *tdesc_find_feature (const struct target_desc *, + const char *name); /* Return the name of FEATURE. */ @@ -253,4 +253,9 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name, int regnum, int save_restore, const char *group, int bitsize, const char *type); +void tdesc_rescale_vector_types (struct tdesc_feature *feature, int scale); + +void tdesc_rescale_registers (struct tdesc_feature *feature, char *type_name, + int scale); + #endif /* TARGET_DESCRIPTIONS_H */ diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 40f04786b08613d59d94868e5a9c02b9c9df6520..62155a5a94f423ee88af739e3070ff78b 6f75661 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -491,7 +491,7 @@ tdesc_has_registers (const struct target_desc *target_desc) /* Return the feature with the given name, if present, or NULL if the named feature is not found. */ -const struct tdesc_feature * +struct tdesc_feature * tdesc_find_feature (const struct target_desc *target_desc, const char *name)