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