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