xref: /netbsd-src/external/gpl3/gdb/dist/gdbserver/linux-aarch64-ipa.cc (revision 32d1c65c71fbdb65a012e8392a62a757dd6853e9)
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 
47 static 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 
125 void
126 supply_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 
137 ULONGEST
138 get_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 
151 const struct target_desc *
152 get_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 
163 void *
164 alloc_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 
203 void
204 initialize_low_tracepoint (void)
205 {
206   /* SVE, pauth, MTE and TLS not yet supported.  */
207   aarch64_linux_read_description ({});
208 }
209