1/* GNU/Linux/AArch64 specific low level interface, for the in-process
2   agent library for GDB.
3
4   Copyright (C) 2015-2024 Free Software Foundation, Inc.
5
6   This file is part of GDB.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3 of the License, or
11   (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20
21#include <sys/mman.h>
22#include "tracepoint.h"
23#include <elf.h>
24#ifdef HAVE_GETAUXVAL
25#include <sys/auxv.h>
26#endif
27#include "linux-aarch64-tdesc.h"
28
29/* Each register saved by the jump pad is in a 16 byte cell.  */
30#define FT_CR_SIZE 16
31
32#define FT_CR_FPCR	0
33#define FT_CR_FPSR	1
34#define FT_CR_CPSR	2
35#define FT_CR_PC	3
36#define FT_CR_SP	4
37#define FT_CR_X0	5
38#define FT_CR_GPR(n)	(FT_CR_X0 + (n))
39#define FT_CR_FPR(n)	(FT_CR_GPR (31) + (n))
40
41/* Mapping between registers collected by the jump pad and GDB's register
42   array layout used by regcache.
43
44   See linux-aarch64-low.c (aarch64_install_fast_tracepoint_jump_pad) for
45   more details.  */
46
47static const int aarch64_ft_collect_regmap[] = {
48  FT_CR_GPR (0),
49  FT_CR_GPR (1),
50  FT_CR_GPR (2),
51  FT_CR_GPR (3),
52  FT_CR_GPR (4),
53  FT_CR_GPR (5),
54  FT_CR_GPR (6),
55  FT_CR_GPR (7),
56  FT_CR_GPR (8),
57  FT_CR_GPR (9),
58  FT_CR_GPR (10),
59  FT_CR_GPR (11),
60  FT_CR_GPR (12),
61  FT_CR_GPR (13),
62  FT_CR_GPR (14),
63  FT_CR_GPR (15),
64  FT_CR_GPR (16),
65  FT_CR_GPR (17),
66  FT_CR_GPR (18),
67  FT_CR_GPR (19),
68  FT_CR_GPR (20),
69  FT_CR_GPR (21),
70  FT_CR_GPR (22),
71  FT_CR_GPR (23),
72  FT_CR_GPR (24),
73  FT_CR_GPR (25),
74  FT_CR_GPR (26),
75  FT_CR_GPR (27),
76  FT_CR_GPR (28),
77  /* FP */
78  FT_CR_GPR (29),
79  /* LR */
80  FT_CR_GPR (30),
81  FT_CR_SP,
82  FT_CR_PC,
83  FT_CR_CPSR,
84  FT_CR_FPR (0),
85  FT_CR_FPR (1),
86  FT_CR_FPR (2),
87  FT_CR_FPR (3),
88  FT_CR_FPR (4),
89  FT_CR_FPR (5),
90  FT_CR_FPR (6),
91  FT_CR_FPR (7),
92  FT_CR_FPR (8),
93  FT_CR_FPR (9),
94  FT_CR_FPR (10),
95  FT_CR_FPR (11),
96  FT_CR_FPR (12),
97  FT_CR_FPR (13),
98  FT_CR_FPR (14),
99  FT_CR_FPR (15),
100  FT_CR_FPR (16),
101  FT_CR_FPR (17),
102  FT_CR_FPR (18),
103  FT_CR_FPR (19),
104  FT_CR_FPR (20),
105  FT_CR_FPR (21),
106  FT_CR_FPR (22),
107  FT_CR_FPR (23),
108  FT_CR_FPR (24),
109  FT_CR_FPR (25),
110  FT_CR_FPR (26),
111  FT_CR_FPR (27),
112  FT_CR_FPR (28),
113  FT_CR_FPR (29),
114  FT_CR_FPR (30),
115  FT_CR_FPR (31),
116  FT_CR_FPSR,
117  FT_CR_FPCR
118};
119
120#define AARCH64_NUM_FT_COLLECT_GREGS \
121  (sizeof (aarch64_ft_collect_regmap) / sizeof(aarch64_ft_collect_regmap[0]))
122
123/* Fill in REGCACHE with registers saved by the jump pad in BUF.  */
124
125void
126supply_fast_tracepoint_registers (struct regcache *regcache,
127				  const unsigned char *buf)
128{
129  int i;
130
131  for (i = 0; i < AARCH64_NUM_FT_COLLECT_GREGS; i++)
132    supply_register (regcache, i,
133		     ((char *) buf)
134		     + (aarch64_ft_collect_regmap[i] * FT_CR_SIZE));
135}
136
137ULONGEST
138get_raw_reg (const unsigned char *raw_regs, int regnum)
139{
140  if (regnum >= AARCH64_NUM_FT_COLLECT_GREGS)
141    return 0;
142
143  return *(ULONGEST *) (raw_regs
144			+ aarch64_ft_collect_regmap[regnum] * FT_CR_SIZE);
145}
146
147/* Return target_desc to use for IPA, given the tdesc index passed by
148   gdbserver.  Index is ignored, since we have only one tdesc
149   at the moment.  SVE, pauth, MTE and TLS not yet supported.  */
150
151const struct target_desc *
152get_ipa_tdesc (int idx)
153{
154  return aarch64_linux_read_description ({});
155}
156
157/* Allocate buffer for the jump pads.  The branch instruction has a reach
158   of +/- 128MiB, and the executable is loaded at 0x400000 (4MiB).
159   To maximize the area of executable that can use tracepoints, try
160   allocating at 0x400000 - size initially, decreasing until we hit
161   a free area.  */
162
163void *
164alloc_jump_pad_buffer (size_t size)
165{
166  uintptr_t addr;
167  uintptr_t exec_base = getauxval (AT_PHDR);
168  int pagesize;
169  void *res;
170
171  if (exec_base == 0)
172    exec_base = 0x400000;
173
174  pagesize = sysconf (_SC_PAGE_SIZE);
175  if (pagesize == -1)
176    perror_with_name ("sysconf");
177
178  addr = exec_base - size;
179
180  /* size should already be page-aligned, but this can't hurt.  */
181  addr &= ~(pagesize - 1);
182
183  /* Search for a free area.  If we hit 0, we're out of luck.  */
184  for (; addr; addr -= pagesize)
185    {
186      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
187      res = mmap ((void *) addr, size,
188		  PROT_READ | PROT_WRITE | PROT_EXEC,
189		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
190
191      /* If we got what we wanted, return.  */
192      if ((uintptr_t) res == addr)
193	return res;
194
195      /* If we got a mapping, but at a wrong address, undo it.  */
196      if (res != MAP_FAILED)
197	munmap (res, size);
198    }
199
200  return NULL;
201}
202
203void
204initialize_low_tracepoint (void)
205{
206  /* SVE, pauth, MTE and TLS not yet supported.  */
207  aarch64_linux_read_description ({});
208}
209