From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 6IhWKeRHkF+UGAAAWB0awg (envelope-from ) for ; Wed, 21 Oct 2020 10:38:28 -0400 Received: by simark.ca (Postfix, from userid 112) id A6D711EFC3; Wed, 21 Oct 2020 10:38:28 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 86FB91E58E for ; Wed, 21 Oct 2020 10:38:27 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3C42E3953CE6; Wed, 21 Oct 2020 14:38:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3C42E3953CE6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1603291107; bh=9IW7ybn62DQ85YziykT+sqqy2VqWbSM5vvLDSwd9Fsc=; h=Subject:To:References:Date:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=Qao4ssv+J6JnMNE+RMTjcf7Za+8H1sGg5s1oA255bBnzdssK0dI+9RZ0YKnhpL67V CIXL4n7Js9RdRB07KGL4rTLTf3ai2rc8fw3Ol1cTy4iC+xf8ak4VU47JB9vAYHXq32 3VnnRY/KHPkmWMCvhd8SZHyvdA4tQbs34c0skOwQ= Received: from mail-qk1-x744.google.com (mail-qk1-x744.google.com [IPv6:2607:f8b0:4864:20::744]) by sourceware.org (Postfix) with ESMTPS id 59BBC39518A8 for ; Wed, 21 Oct 2020 14:38:23 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 59BBC39518A8 Received: by mail-qk1-x744.google.com with SMTP id k9so2664096qki.6 for ; Wed, 21 Oct 2020 07:38:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=9IW7ybn62DQ85YziykT+sqqy2VqWbSM5vvLDSwd9Fsc=; b=sB1y2Y9R/56LXLYQhnokvOXONCmf+fAMKIchV9sdEQFgeN5ofctxbqhrqHXcHTqRQb mIfMIzn/PG7mCErkyfiFp15RbRLMxhQ3onpjdLMdhWcx6ZcRPV1fJ0x2XPtgQjYwIwn7 NxyugMdZoF4UXJA6ADGlkddFc5HL2fmrLVQzUcDOpfHoHvPnew1ilnc1RH1xXg8oFCRp g3JpWJsogZFf9lqWxR9T09SGzzCmBgyvNPV7dpAHZ8eq5yw6WVQkJufX1mBGG4wyjfcH sI1mrGHOmPDPZWPOWDBcWDMt6a+JQHRcp8mdaRcjjnMuosTgMbZNfpaFml3qoag1c7MD WXSA== X-Gm-Message-State: AOAM53153kpmdY7Z3BUbmFS8tCfuHNZ6+29mJEsRWbcYooDx4ApMAARX Ejja8547KeOb/DZg2Er1GF0mn/9zYJuhgA== X-Google-Smtp-Source: ABdhPJweOBjvxxROipEDPz9WbeI/NEu+Op3qT8pkYIrW7+G9xWE/+HS+otSnHizqTZEt0WoMOVYmPQ== X-Received: by 2002:a05:620a:2232:: with SMTP id n18mr3385523qkh.331.1603291102418; Wed, 21 Oct 2020 07:38:22 -0700 (PDT) Received: from ?IPv6:2804:7f0:8283:fe4b:b9b1:f72a:8f1:600? ([2804:7f0:8283:fe4b:b9b1:f72a:8f1:600]) by smtp.gmail.com with ESMTPSA id t3sm1268499qtq.24.2020.10.21.07.38.19 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 21 Oct 2020 07:38:21 -0700 (PDT) Subject: Re: [PATCH v2] Support for corefiles for arm-none-eabi target. To: Fredrik Hederstierna , gdb-patches@sourceware.org, simark@simark.ca, Alan.Hayward@arm.com, paulmathieu@google.com References: <20201020215817.25264-1-fredrik@hederstierna.com> Message-ID: <45149673-46bb-d32f-b413-5c72739ef074@linaro.org> Date: Wed, 21 Oct 2020 11:38:17 -0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0 MIME-Version: 1.0 In-Reply-To: <20201020215817.25264-1-fredrik@hederstierna.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-US Content-Transfer-Encoding: 7bit X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Luis Machado via Gdb-patches Reply-To: Luis Machado Errors-To: gdb-patches-bounces@sourceware.org Sender: "Gdb-patches" Hi, Apologies for the delay in replying. I think this still needs some more work to cut it down to the bare essentials for a core file. I see quite a few things that are linux-specific and that shouldn't be included in a potential all-arch bare-metal core file format. As Simon said, siginfo and auxv are *nix concepts. HWCAP_* constants are also *nix/Linux concepts. So those should be dropped unless there is good reason to include them. If we require some of their data, then we should think of a way to make that available. For example, AUXV's entry point information. We should really discuss what the generic core file format for bare-metal targets will look like before having a possible patch to implement it. At least that's my take on it. Otherwise we risk having an implementation without a formal definition. And core files are already somewhat vaguely-defined anyway. On 10/20/20 6:58 PM, Fredrik Hederstierna wrote: > From: fredrikhederstierna > > --- > gdb/arm-none-tdep.c | 368 ++++++++++++++++++++++++++++++++++++++++++++ > gdb/arm-none-tdep.h | 60 ++++++++ > gdb/arm-tdep.c | 8 + > gdb/configure.tgt | 6 +- > gdb/none-tdep.c | 335 ++++++++++++++++++++++++++++++++++++++++ > gdb/none-tdep.h | 39 +++++ > 6 files changed, 815 insertions(+), 1 deletion(-) > create mode 100644 gdb/arm-none-tdep.c > create mode 100644 gdb/arm-none-tdep.h > create mode 100644 gdb/none-tdep.c > create mode 100644 gdb/none-tdep.h > > diff --git a/gdb/arm-none-tdep.c b/gdb/arm-none-tdep.c > new file mode 100644 > index 0000000000..9d83a8b913 > --- /dev/null > +++ b/gdb/arm-none-tdep.c > @@ -0,0 +1,368 @@ > +/* none on ARM target support. > + > + Copyright (C) 2020 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#include "defs.h" > +#include "target.h" > +#include "value.h" > +#include "gdbtypes.h" > +#include "gdbcore.h" > +#include "frame.h" > +#include "regcache.h" > +#include "solib-svr4.h" > +#include "osabi.h" > +#include "regset.h" > +#include "trad-frame.h" > +#include "tramp-frame.h" > +#include "breakpoint.h" > +#include "auxv.h" > + > +#include "aarch32-tdep.h" > +#include "arch/arm.h" > +#include "arm-tdep.h" > +#include "arm-none-tdep.h" > +#include "glibc-tdep.h" > +#include "arch-utils.h" > +#include "inferior.h" > +#include "gdbthread.h" > +#include "symfile.h" > + > +#include "cli/cli-utils.h" > +#include "stap-probe.h" > +#include "parser-defs.h" > +#include "user-regs.h" > +#include > + > +#include "elf-bfd.h" > +#include "coff/internal.h" > +#include "elf/arm.h" > + > +#include "elf/common.h" > + > +/* ---- based on arm-linux-tdep.h ---- */ > + > +#define ARM_NONE_SIZEOF_NWFPE (8 * ARM_FP_REGISTER_SIZE \ > + + 2 * ARM_INT_REGISTER_SIZE \ > + + 8 + ARM_INT_REGISTER_SIZE) > + > +/* The index to access CSPR in user_regs defined in GLIBC. */ > +#define ARM_CPSR_GREGNUM 16 > + > +/* Support for register format used by the NWFPE FPA emulator. Each > + register takes three words, where either the first one, two, or > + three hold a single, double, or extended precision value (depending > + on the corresponding tag). The register set is eight registers, > + followed by the fpsr and fpcr, followed by eight tag bytes, and a > + final word flag which indicates whether NWFPE has been > + initialized. */ > + > +#define NWFPE_FPSR_OFFSET (8 * ARM_FP_REGISTER_SIZE) > +#define NWFPE_FPCR_OFFSET (NWFPE_FPSR_OFFSET + ARM_INT_REGISTER_SIZE) > +#define NWFPE_TAGS_OFFSET (NWFPE_FPCR_OFFSET + ARM_INT_REGISTER_SIZE) > +#define NWFPE_INITFLAG_OFFSET (NWFPE_TAGS_OFFSET + 8) > + > +/* Reuse ARM GNU/Linux HWCAP values for none. These are in defined in > + in current kernels. */ > +#define HWCAP_VFP 64 > +#define HWCAP_IWMMXT 512 > +#define HWCAP_NEON 4096 > +#define HWCAP_VFPv3 8192 > +#define HWCAP_VFPv3D16 16384 > + > +/* Core file and register set support. */ > + > +#define ARM_NONE_SIZEOF_GREGSET (18 * ARM_INT_REGISTER_SIZE) > + > +/* ---- based on arm-linux-tdep.c ---- */ > + > +void > +arm_none_supply_gregset (const struct regset *regset, > + struct regcache *regcache, > + int regnum, const void *gregs_buf, size_t len) > +{ > + struct gdbarch *gdbarch = regcache->arch (); > + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); > + const gdb_byte *gregs = (const gdb_byte *) gregs_buf; > + int regno; > + CORE_ADDR reg_pc; > + gdb_byte pc_buf[ARM_INT_REGISTER_SIZE]; > + > + for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) > + if (regnum == -1 || regnum == regno) > + regcache->raw_supply (regno, gregs + ARM_INT_REGISTER_SIZE * regno); > + > + if (regnum == ARM_PS_REGNUM || regnum == -1) > + { > + if (arm_apcs_32) > + regcache->raw_supply (ARM_PS_REGNUM, > + gregs + ARM_INT_REGISTER_SIZE * ARM_CPSR_GREGNUM); > + else > + regcache->raw_supply (ARM_PS_REGNUM, > + gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM); > + } > + > + if (regnum == ARM_PC_REGNUM || regnum == -1) > + { > + reg_pc = extract_unsigned_integer ( > + gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM, > + ARM_INT_REGISTER_SIZE, byte_order); > + reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc); > + store_unsigned_integer (pc_buf, ARM_INT_REGISTER_SIZE, byte_order, > + reg_pc); > + regcache->raw_supply (ARM_PC_REGNUM, pc_buf); > + } > +} > + > +void > +arm_none_collect_gregset (const struct regset *regset, > + const struct regcache *regcache, > + int regnum, void *gregs_buf, size_t len) > +{ > + gdb_byte *gregs = (gdb_byte *) gregs_buf; > + int regno; > + > + for (regno = ARM_A1_REGNUM; regno < ARM_PC_REGNUM; regno++) > + if (regnum == -1 || regnum == regno) > + regcache->raw_collect (regno, > + gregs + ARM_INT_REGISTER_SIZE * regno); > + > + if (regnum == ARM_PS_REGNUM || regnum == -1) > + { > + if (arm_apcs_32) > + regcache->raw_collect (ARM_PS_REGNUM, > + gregs + ARM_INT_REGISTER_SIZE * ARM_CPSR_GREGNUM); > + else > + regcache->raw_collect (ARM_PS_REGNUM, > + gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM); > + } > + > + if (regnum == ARM_PC_REGNUM || regnum == -1) > + regcache->raw_collect (ARM_PC_REGNUM, > + gregs + ARM_INT_REGISTER_SIZE * ARM_PC_REGNUM); > +} > + > +/* Support for register format used by the NWFPE FPA emulator. */ > + > +#define typeNone 0x00 > +#define typeSingle 0x01 > +#define typeDouble 0x02 > +#define typeExtended 0x03 > + > +void > +arm_none_supply_nwfpe_register (struct regcache *regcache, int regno, > + const gdb_byte *regs) > +{ > + const gdb_byte *reg_data; > + gdb_byte reg_tag; > + gdb_byte buf[ARM_FP_REGISTER_SIZE]; > + > + reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE; > + reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET]; > + memset (buf, 0, ARM_FP_REGISTER_SIZE); > + > + switch (reg_tag) > + { > + case typeSingle: > + memcpy (buf, reg_data, 4); > + break; > + case typeDouble: > + memcpy (buf, reg_data + 4, 4); > + memcpy (buf + 4, reg_data, 4); > + break; > + case typeExtended: > + /* We want sign and exponent, then least significant bits, > + then most significant. NWFPE does sign, most, least. */ > + memcpy (buf, reg_data, 4); > + memcpy (buf + 4, reg_data + 8, 4); > + memcpy (buf + 8, reg_data + 4, 4); > + break; > + default: > + break; > + } > + > + regcache->raw_supply (regno, buf); > +} > + > +void > +arm_none_collect_nwfpe_register (const struct regcache *regcache, int regno, > + gdb_byte *regs) > +{ > + gdb_byte *reg_data; > + gdb_byte reg_tag; > + gdb_byte buf[ARM_FP_REGISTER_SIZE]; > + > + regcache->raw_collect (regno, buf); > + > + /* NOTE drow/2006-06-07: This code uses the tag already in the > + register buffer. I've preserved that when moving the code > + from the native file to the target file. But this doesn't > + always make sense. */ > + > + reg_data = regs + (regno - ARM_F0_REGNUM) * ARM_FP_REGISTER_SIZE; > + reg_tag = regs[(regno - ARM_F0_REGNUM) + NWFPE_TAGS_OFFSET]; > + > + switch (reg_tag) > + { > + case typeSingle: > + memcpy (reg_data, buf, 4); > + break; > + case typeDouble: > + memcpy (reg_data, buf + 4, 4); > + memcpy (reg_data + 4, buf, 4); > + break; > + case typeExtended: > + memcpy (reg_data, buf, 4); > + memcpy (reg_data + 4, buf + 8, 4); > + memcpy (reg_data + 8, buf + 4, 4); > + break; > + default: > + break; > + } > +} > + > +void > +arm_none_supply_nwfpe (const struct regset *regset, > + struct regcache *regcache, > + int regnum, const void *regs_buf, size_t len) > +{ > + const gdb_byte *regs = (const gdb_byte *) regs_buf; > + int regno; > + > + if (regnum == ARM_FPS_REGNUM || regnum == -1) > + regcache->raw_supply (ARM_FPS_REGNUM, > + regs + NWFPE_FPSR_OFFSET); > + > + for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) > + if (regnum == -1 || regnum == regno) > + arm_none_supply_nwfpe_register (regcache, regno, regs); > +} > + > +void > +arm_none_collect_nwfpe (const struct regset *regset, > + const struct regcache *regcache, > + int regnum, void *regs_buf, size_t len) > +{ > + gdb_byte *regs = (gdb_byte *) regs_buf; > + int regno; > + > + for (regno = ARM_F0_REGNUM; regno <= ARM_F7_REGNUM; regno++) > + if (regnum == -1 || regnum == regno) > + arm_none_collect_nwfpe_register (regcache, regno, regs); > + > + if (regnum == ARM_FPS_REGNUM || regnum == -1) > + regcache->raw_collect (ARM_FPS_REGNUM, > + regs + ARM_INT_REGISTER_SIZE * ARM_FPS_REGNUM); > +} > + > +/* Support VFP register format. */ > + > +#define ARM_NONE_SIZEOF_VFP (32 * 8 + 4) > + > +static void > +arm_none_supply_vfp (const struct regset *regset, > + struct regcache *regcache, > + int regnum, const void *regs_buf, size_t len) > +{ > + const gdb_byte *regs = (const gdb_byte *) regs_buf; > + int regno; > + > + if (regnum == ARM_FPSCR_REGNUM || regnum == -1) > + regcache->raw_supply (ARM_FPSCR_REGNUM, regs + 32 * 8); > + > + for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++) > + if (regnum == -1 || regnum == regno) > + regcache->raw_supply (regno, regs + (regno - ARM_D0_REGNUM) * 8); > +} > + > +static void > +arm_none_collect_vfp (const struct regset *regset, > + const struct regcache *regcache, > + int regnum, void *regs_buf, size_t len) > +{ > + gdb_byte *regs = (gdb_byte *) regs_buf; > + int regno; > + > + if (regnum == ARM_FPSCR_REGNUM || regnum == -1) > + regcache->raw_collect (ARM_FPSCR_REGNUM, regs + 32 * 8); > + > + for (regno = ARM_D0_REGNUM; regno <= ARM_D31_REGNUM; regno++) > + if (regnum == -1 || regnum == regno) > + regcache->raw_collect (regno, regs + (regno - ARM_D0_REGNUM) * 8); > +} > + > +static const struct regset arm_none_gregset = > + { > + NULL, arm_none_supply_gregset, arm_none_collect_gregset > + }; > + > +static const struct regset arm_none_fpregset = > + { > + NULL, arm_none_supply_nwfpe, arm_none_collect_nwfpe > + }; > + > +static const struct regset arm_none_vfpregset = > + { > + NULL, arm_none_supply_vfp, arm_none_collect_vfp > + }; > + > +/* Iterate over core file register note sections. */ > + > +void > +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch, > + iterate_over_regset_sections_cb *cb, > + void *cb_data, > + const struct regcache *regcache) > +{ > + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); > + > + cb (".reg", ARM_NONE_SIZEOF_GREGSET, ARM_NONE_SIZEOF_GREGSET, > + &arm_none_gregset, NULL, cb_data); > + > + if (tdep->vfp_register_count > 0) > + cb (".reg-arm-vfp", ARM_NONE_SIZEOF_VFP, ARM_NONE_SIZEOF_VFP, > + &arm_none_vfpregset, "VFP floating-point", cb_data); > + else if (tdep->have_fpa_registers) > + cb (".reg2", ARM_NONE_SIZEOF_NWFPE, ARM_NONE_SIZEOF_NWFPE, > + &arm_none_fpregset, "FPA floating-point", cb_data); > +} > + > +/* Determine target description from core file. */ > + > +const struct target_desc * > +arm_none_core_read_description (struct gdbarch *gdbarch, > + struct target_ops *target, > + bfd *abfd) > +{ > + CORE_ADDR arm_hwcap = 0; > + if (target_auxv_search (target, AT_HWCAP, &arm_hwcap) != 1) > + return nullptr; > + > + if (arm_hwcap & HWCAP_VFP) > + { > + /* NEON implies VFPv3-D32 or no-VFP unit. Say that we only support > + Neon with VFPv3-D32. */ > + if (arm_hwcap & HWCAP_NEON) > + return aarch32_read_description (); > + else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3) > + return arm_read_description (ARM_FP_TYPE_VFPV3); > + > + return arm_read_description (ARM_FP_TYPE_VFPV2); > + } > + > + return nullptr; > +} > diff --git a/gdb/arm-none-tdep.h b/gdb/arm-none-tdep.h > new file mode 100644 > index 0000000000..7927c0aff3 > --- /dev/null > +++ b/gdb/arm-none-tdep.h > @@ -0,0 +1,60 @@ > +/* none on ARM target support, prototypes. > + > + Copyright (C) 2020 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#ifndef ARM_NONE_TDEP_H > +#define ARM_NONE_TDEP_H > + > +#include "gdbarch.h" > +#include "target.h" > +#include "bfd.h" > + > +struct regset; > +struct regcache; > + > +void arm_none_supply_gregset (const struct regset *regset, > + struct regcache *regcache, > + int regnum, const void *gregs_buf, size_t len); > +void arm_none_collect_gregset (const struct regset *regset, > + const struct regcache *regcache, > + int regnum, void *gregs_buf, size_t len); > + > +void arm_none_supply_nwfpe_register (struct regcache *regcache, int regno, > + const gdb_byte *regs); > +void arm_none_collect_nwfpe_register (const struct regcache *regcache, int regno, > + gdb_byte *regs); > + > +void arm_none_supply_nwfpe (const struct regset *regset, > + struct regcache *regcache, > + int regnum, const void *regs_buf, size_t len); > +void arm_none_collect_nwfpe (const struct regset *regset, > + const struct regcache *regcache, > + int regnum, void *regs_buf, size_t len); > + > +void > +arm_none_iterate_over_regset_sections (struct gdbarch *gdbarch, > + iterate_over_regset_sections_cb *cb, > + void *cb_data, > + const struct regcache *regcache); > + > +const struct target_desc * > +arm_none_core_read_description (struct gdbarch *gdbarch, > + struct target_ops *target, > + bfd *abfd); > + > +#endif /* ARM_NONE_TDEP_H */ > diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c > index a214f22d7a..be47cc2228 100644 > --- a/gdb/arm-tdep.c > +++ b/gdb/arm-tdep.c > @@ -50,6 +50,8 @@ > #include "arch/arm.h" > #include "arch/arm-get-next-pcs.h" > #include "arm-tdep.h" > +#include "none-tdep.h" > +#include "arm-none-tdep.h" > #include "gdb/sim-arm.h" > > #include "elf-bfd.h" > @@ -9453,6 +9455,12 @@ arm_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) > /* Virtual tables. */ > set_gdbarch_vbit_in_delta (gdbarch, 1); > > + /* Default none core file support, can be overridden by osabi. */ > + none_init_corefile (info, gdbarch); > + set_gdbarch_iterate_over_regset_sections (gdbarch, > + arm_none_iterate_over_regset_sections); > + set_gdbarch_core_read_description (gdbarch, arm_none_core_read_description); > + > /* Hook in the ABI-specific overrides, if they have been registered. */ > gdbarch_init_osabi (info, gdbarch); > > diff --git a/gdb/configure.tgt b/gdb/configure.tgt > index d865ecdcb6..f4a1540464 100644 > --- a/gdb/configure.tgt > +++ b/gdb/configure.tgt > @@ -64,7 +64,8 @@ arc*-*-*) > > arm*-*-*) > cpu_obs="aarch32-tdep.o arch/aarch32.o arch/arm.o \ > - arch/arm-get-next-pcs.o arm-tdep.o";; > + arch/arm-get-next-pcs.o arm-tdep.o \ > + none-tdep.o arm-none-tdep.o";; > > hppa*-*-*) > # Target: HP PA-RISC > @@ -798,4 +799,7 @@ for t in x ${gdb_target_obs}; do > if test "$t" = linux-tdep.o; then > gdb_have_gcore=true > fi > + if test "$t" = arm-none-tdep.o; then > + gdb_have_gcore=true > + fi > done > diff --git a/gdb/none-tdep.c b/gdb/none-tdep.c > new file mode 100644 > index 0000000000..5ac5c6c707 > --- /dev/null > +++ b/gdb/none-tdep.c > @@ -0,0 +1,335 @@ > +/* Target-dependent code for none, architecture independent. > + > + Copyright (C) 2020 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#include "defs.h" > +#include "gdbtypes.h" > +#include "none-tdep.h" > +#include "auxv.h" > +#include "target.h" > +#include "gdbthread.h" > +#include "gdbcore.h" > +#include "regcache.h" > +#include "regset.h" > +#include "elf/common.h" > +#include "elf-bfd.h" /* for elfcore_write_* */ > +#include "inferior.h" > +#include "cli/cli-utils.h" > +#include "arch-utils.h" > +#include "gdb_obstack.h" > +#include "observable.h" > +#include "objfiles.h" > +#include "infcall.h" > +#include "gdbcmd.h" > +#include "gdb_regex.h" > +#include "gdbsupport/enum-flags.h" > +#include "gdbsupport/gdb_optional.h" > + > +#include > + > +/* ---- based on linux-tdep.c ---- */ > + > +/* Structure for passing information from > + none_collect_thread_registers via an iterator to > + none_collect_regset_section_cb. */ > + > +struct none_collect_regset_section_cb_data > +{ > + struct gdbarch *gdbarch; > + const struct regcache *regcache; > + bfd *obfd; > + char *note_data; > + int *note_size; > + unsigned long lwp; > + enum gdb_signal stop_signal; > + int abort_iteration; > +}; > + > +/* Callback for iterate_over_regset_sections that records a single > + regset in the corefile note section. */ > + > +static void > +none_collect_regset_section_cb (const char *sect_name, int supply_size, > + int collect_size, const struct regset *regset, > + const char *human_name, void *cb_data) > +{ > + struct none_collect_regset_section_cb_data *data > + = (struct none_collect_regset_section_cb_data *) cb_data; > + bool variable_size_section = (regset != NULL > + && regset->flags & REGSET_VARIABLE_SIZE); > + > + if (!variable_size_section) > + gdb_assert (supply_size == collect_size); > + > + if (data->abort_iteration) > + return; > + > + gdb_assert (regset && regset->collect_regset); > + > + /* This is intentionally zero-initialized by using std::vector, so > + that any padding bytes in the core file will show as 0. */ > + std::vector buf (collect_size); > + > + regset->collect_regset (regset, data->regcache, -1, buf.data (), > + collect_size); > + > + /* PRSTATUS still needs to be treated specially. */ > + if (strcmp (sect_name, ".reg") == 0) > + data->note_data = (char *) elfcore_write_prstatus > + (data->obfd, data->note_data, data->note_size, data->lwp, > + gdb_signal_to_host (data->stop_signal), buf.data ()); > + else > + data->note_data = (char *) elfcore_write_register_note > + (data->obfd, data->note_data, data->note_size, > + sect_name, buf.data (), collect_size); > + > + if (data->note_data == NULL) > + data->abort_iteration = 1; > +} > + > +/* Records the thread's register state for the corefile note > + section. */ > + > +static char * > +none_collect_thread_registers (const struct regcache *regcache, > + ptid_t ptid, bfd *obfd, > + char *note_data, int *note_size, > + enum gdb_signal stop_signal) > +{ > + struct gdbarch *gdbarch = regcache->arch (); > + struct none_collect_regset_section_cb_data data; > + > + data.gdbarch = gdbarch; > + data.regcache = regcache; > + data.obfd = obfd; > + data.note_data = note_data; > + data.note_size = note_size; > + data.stop_signal = stop_signal; > + data.abort_iteration = 0; > + > + /* For remote targets the LWP may not be available, so use the TID. */ > + data.lwp = ptid.lwp (); > + if (!data.lwp) > + data.lwp = ptid.tid (); > + > + gdbarch_iterate_over_regset_sections (gdbarch, > + none_collect_regset_section_cb, > + &data, regcache); > + return data.note_data; > +} > + > +/* Fetch the siginfo data for the specified thread, if it exists. If > + there is no data, or we could not read it, return an empty > + buffer. */ > + > +static gdb::byte_vector > +none_get_siginfo_data (thread_info *thread, struct gdbarch *gdbarch) > +{ > + struct type *siginfo_type; > + LONGEST bytes_read; > + > + if (!gdbarch_get_siginfo_type_p (gdbarch)) > + return gdb::byte_vector (); > + > + scoped_restore_current_thread save_current_thread; > + switch_to_thread (thread); > + > + siginfo_type = gdbarch_get_siginfo_type (gdbarch); > + > + gdb::byte_vector buf (TYPE_LENGTH (siginfo_type)); > + > + bytes_read = target_read (current_top_target (), TARGET_OBJECT_SIGNAL_INFO, NULL, > + buf.data (), 0, TYPE_LENGTH (siginfo_type)); > + if (bytes_read != TYPE_LENGTH (siginfo_type)) > + buf.clear (); > + > + return buf; > +} > + > +struct none_corefile_thread_data > +{ > + struct gdbarch *gdbarch; > + bfd *obfd; > + char *note_data; > + int *note_size; > + enum gdb_signal stop_signal; > +}; > + > +/* Records the thread's register state for the corefile note > + section. */ > + > +static void > +none_corefile_thread (struct thread_info *info, > + struct none_corefile_thread_data *args) > +{ > + struct regcache *regcache; > + > + regcache = get_thread_arch_regcache (info->inf->process_target (), > + info->ptid, args->gdbarch); > + > + target_fetch_registers (regcache, -1); > + gdb::byte_vector siginfo_data = none_get_siginfo_data (info, args->gdbarch); > + > + args->note_data = none_collect_thread_registers > + (regcache, info->ptid, args->obfd, args->note_data, > + args->note_size, args->stop_signal); > + > + /* Don't return anything if we got no register information above, > + such a core file is useless. */ > + if (args->note_data != NULL) > + if (!siginfo_data.empty ()) > + args->note_data = elfcore_write_note (args->obfd, > + args->note_data, > + args->note_size, > + "CORE", NT_SIGINFO, > + siginfo_data.data (), > + siginfo_data.size ()); > +} > + > +/* Find the signalled thread. In case there's more than one signalled > + thread, prefer the current thread, if it is signalled. If no > + thread was signalled, default to the current thread, unless it has > + exited, in which case return NULL. */ > + > +static thread_info * > +find_signalled_thread () > +{ > + thread_info *curr_thr = inferior_thread (); > + if (curr_thr->state != THREAD_EXITED > + && curr_thr->suspend.stop_signal != GDB_SIGNAL_0) > + return curr_thr; > + > + for (thread_info *thr : current_inferior ()->non_exited_threads ()) > + if (thr->suspend.stop_signal != GDB_SIGNAL_0) > + return thr; > + > + /* Default to the current thread, unless it has exited. */ > + if (curr_thr->state != THREAD_EXITED) > + return curr_thr; > + > + return nullptr; > +} > + > +/* Fills the "to_make_corefile_note" target vector. Builds the note > + section for a corefile, and returns it in a malloc buffer. */ > + > +char * > +none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size, > + none_collect_thread_registers_ftype collect) > +{ > + struct none_corefile_thread_data thread_args; > + char *note_data = NULL; > + > + /* Process information. */ > + if (get_exec_file (0)) > + { > + const char *fname = lbasename (get_exec_file (0)); > + char *psargs = xstrdup (fname); > + > + if (get_inferior_args ()) > + psargs = reconcat (psargs, psargs, " ", get_inferior_args (), > + (char *) NULL); > + > + note_data = elfcore_write_prpsinfo (obfd, note_data, note_size, > + fname, psargs); > + xfree (psargs); > + } > + > + if (!note_data) > + return NULL; > + > + /* Thread register information. */ > + try > + { > + update_thread_list (); > + } > + catch (const gdb_exception_error &e) > + { > + exception_print (gdb_stderr, e); > + } > + > + /* Like the kernel, prefer dumping the signalled thread first. > + "First thread" is what tools use to infer the signalled > + thread. */ > + thread_info *signalled_thr = find_signalled_thread (); > + > + thread_args.gdbarch = gdbarch; > + thread_args.obfd = obfd; > + thread_args.note_data = note_data; > + thread_args.note_size = note_size; > + if (signalled_thr != nullptr) > + thread_args.stop_signal = signalled_thr->suspend.stop_signal; > + else > + thread_args.stop_signal = GDB_SIGNAL_0; > + > + if (signalled_thr != nullptr) > + none_corefile_thread (signalled_thr, &thread_args); > + for (thread_info *thr : current_inferior ()->non_exited_threads ()) > + { > + if (thr == signalled_thr) > + continue; > + > + none_corefile_thread (thr, &thread_args); > + } > + > + note_data = thread_args.note_data; > + if (!note_data) > + return NULL; > + > + /* Auxillary vector. */ > + gdb::optional auxv = > + target_read_alloc (current_top_target (), TARGET_OBJECT_AUXV, NULL); > + if (auxv && !auxv->empty ()) > + { > + note_data = elfcore_write_note (obfd, note_data, note_size, > + "CORE", NT_AUXV, auxv->data (), > + auxv->size ()); > + if (!note_data) > + return NULL; > + } > + > + /* make_cleanup (xfree, note_data); */ > + return note_data; > +} > + > +static char * > +none_make_corefile_notes_1 (struct gdbarch *gdbarch, bfd *obfd, int *note_size) > +{ > + return none_make_corefile_notes (gdbarch, obfd, note_size, > + none_collect_thread_registers); > +} > + > +/* Setup default core file support for none targets. > + Can be overridden later by OSABI. */ > + > +void > +none_init_corefile (struct gdbarch_info info, > + struct gdbarch *gdbarch) > +{ > + /* Default core file support. */ > + set_gdbarch_make_corefile_notes (gdbarch, none_make_corefile_notes_1); > +} > + > +/* Provide a prototype to silence -Wmissing-prototypes. */ > +extern initialize_file_ftype _initialize_none_tdep; > + > +void > +_initialize_none_tdep (void) > +{ > + /* No special actions. */ > +} > diff --git a/gdb/none-tdep.h b/gdb/none-tdep.h > new file mode 100644 > index 0000000000..4aea7004d8 > --- /dev/null > +++ b/gdb/none-tdep.h > @@ -0,0 +1,39 @@ > +/* Target-dependent code for none, architecture independent. > + > + Copyright (C) 2020 Free Software Foundation, Inc. > + > + This file is part of GDB. > + > + This program is free software; you can redistribute it and/or modify > + it under the terms of the GNU General Public License as published by > + the Free Software Foundation; either version 3 of the License, or > + (at your option) any later version. > + > + This program is distributed in the hope that it will be useful, > + but WITHOUT ANY WARRANTY; without even the implied warranty of > + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + GNU General Public License for more details. > + > + You should have received a copy of the GNU General Public License > + along with this program. If not, see . */ > + > +#ifndef NONE_TDEP_H > +#define NONE_TDEP_H > + > +#include "bfd.h" > + > +struct regcache; > + > +typedef char *(*none_collect_thread_registers_ftype) (const struct regcache *, > + ptid_t, > + bfd *, char *, int *, > + enum gdb_signal); > +char * > +none_make_corefile_notes (struct gdbarch *gdbarch, bfd *obfd, int *note_size, > + none_collect_thread_registers_ftype collect); > + > +void > +none_init_corefile (struct gdbarch_info info, > + struct gdbarch *gdbarch); > + > +#endif /* none-tdep.h */ >