xref: /netbsd-src/external/gpl3/gdb/dist/gdbserver/linux-i386-ipa.cc (revision b2c35e17b976cf7ccd7250c86c6f5e95090ed636)
1 /* GNU/Linux/x86 specific low level interface, for the in-process
2    agent library for GDB.
3 
4    Copyright (C) 2010-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 "linux-x86-tdesc.h"
25 #include "gdbsupport/x86-xstate.h"
26 
27 /* GDB register numbers.  */
28 
29 enum i386_gdb_regnum
30 {
31   I386_EAX_REGNUM,		/* %eax */
32   I386_ECX_REGNUM,		/* %ecx */
33   I386_EDX_REGNUM,		/* %edx */
34   I386_EBX_REGNUM,		/* %ebx */
35   I386_ESP_REGNUM,		/* %esp */
36   I386_EBP_REGNUM,		/* %ebp */
37   I386_ESI_REGNUM,		/* %esi */
38   I386_EDI_REGNUM,		/* %edi */
39   I386_EIP_REGNUM,		/* %eip */
40   I386_EFLAGS_REGNUM,		/* %eflags */
41   I386_CS_REGNUM,		/* %cs */
42   I386_SS_REGNUM,		/* %ss */
43   I386_DS_REGNUM,		/* %ds */
44   I386_ES_REGNUM,		/* %es */
45   I386_FS_REGNUM,		/* %fs */
46   I386_GS_REGNUM,		/* %gs */
47   I386_ST0_REGNUM		/* %st(0) */
48 };
49 
50 #define i386_num_regs 16
51 
52 #define FT_CR_EAX 15
53 #define FT_CR_ECX 14
54 #define FT_CR_EDX 13
55 #define FT_CR_EBX 12
56 #define FT_CR_UESP 11
57 #define FT_CR_EBP 10
58 #define FT_CR_ESI 9
59 #define FT_CR_EDI 8
60 #define FT_CR_EIP 7
61 #define FT_CR_EFL 6
62 #define FT_CR_DS 5
63 #define FT_CR_ES 4
64 #define FT_CR_FS 3
65 #define FT_CR_GS 2
66 #define FT_CR_SS 1
67 #define FT_CR_CS 0
68 
69 /* Mapping between the general-purpose registers in jump tracepoint
70    format and GDB's register array layout.  */
71 
72 static const int i386_ft_collect_regmap[] =
73 {
74   FT_CR_EAX * 4, FT_CR_ECX * 4, FT_CR_EDX * 4, FT_CR_EBX * 4,
75   FT_CR_UESP * 4, FT_CR_EBP * 4, FT_CR_ESI * 4, FT_CR_EDI * 4,
76   FT_CR_EIP * 4, FT_CR_EFL * 4, FT_CR_CS * 4, FT_CR_SS * 4,
77   FT_CR_DS * 4, FT_CR_ES * 4, FT_CR_FS * 4, FT_CR_GS * 4
78 };
79 
80 void
81 supply_fast_tracepoint_registers (struct regcache *regcache,
82 				  const unsigned char *buf)
83 {
84   int i;
85 
86   for (i = 0; i < i386_num_regs; i++)
87     {
88       int regval;
89 
90       if (i >= I386_CS_REGNUM && i <= I386_GS_REGNUM)
91 	regval = *(short *) (((char *) buf) + i386_ft_collect_regmap[i]);
92       else
93 	regval = *(int *) (((char *) buf) + i386_ft_collect_regmap[i]);
94 
95       supply_register (regcache, i, &regval);
96     }
97 }
98 
99 ULONGEST
100 get_raw_reg (const unsigned char *raw_regs, int regnum)
101 {
102   /* This should maybe be allowed to return an error code, or perhaps
103      better, have the emit_reg detect this, and emit a constant zero,
104      or something.  */
105 
106   if (regnum > i386_num_regs)
107     return 0;
108   else if (regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM)
109     return *(short *) (raw_regs + i386_ft_collect_regmap[regnum]);
110   else
111     return *(int *) (raw_regs + i386_ft_collect_regmap[regnum]);
112 }
113 
114 #ifdef HAVE_UST
115 
116 #include <ust/processor.h>
117 
118 /* "struct registers" is the UST object type holding the registers at
119    the time of the static tracepoint marker call.  This doesn't
120    contain EIP, but we know what it must have been (the marker
121    address).  */
122 
123 #define ST_REGENTRY(REG)			\
124   {						\
125     offsetof (struct registers, REG),		\
126     sizeof (((struct registers *) NULL)->REG)	\
127   }
128 
129 static struct
130 {
131   int offset;
132   int size;
133 } i386_st_collect_regmap[] =
134   {
135     ST_REGENTRY(eax),
136     ST_REGENTRY(ecx),
137     ST_REGENTRY(edx),
138     ST_REGENTRY(ebx),
139     ST_REGENTRY(esp),
140     ST_REGENTRY(ebp),
141     ST_REGENTRY(esi),
142     ST_REGENTRY(edi),
143     { -1, 0 }, /* eip */
144     ST_REGENTRY(eflags),
145     ST_REGENTRY(cs),
146     ST_REGENTRY(ss),
147   };
148 
149 #define i386_NUM_ST_COLLECT_GREGS \
150   (sizeof (i386_st_collect_regmap) / sizeof (i386_st_collect_regmap[0]))
151 
152 void
153 supply_static_tracepoint_registers (struct regcache *regcache,
154 				    const unsigned char *buf,
155 				    CORE_ADDR pc)
156 {
157   int i;
158   unsigned int newpc = pc;
159 
160   supply_register (regcache, I386_EIP_REGNUM, &newpc);
161 
162   for (i = 0; i < i386_NUM_ST_COLLECT_GREGS; i++)
163     if (i386_st_collect_regmap[i].offset != -1)
164       {
165 	switch (i386_st_collect_regmap[i].size)
166 	  {
167 	  case 4:
168 	    supply_register (regcache, i,
169 			     ((char *) buf)
170 			     + i386_st_collect_regmap[i].offset);
171 	    break;
172 	  case 2:
173 	    {
174 	      unsigned long reg
175 		= * (short *) (((char *) buf)
176 			       + i386_st_collect_regmap[i].offset);
177 	      reg &= 0xffff;
178 	      supply_register (regcache, i, &reg);
179 	    }
180 	    break;
181 	  default:
182 	    internal_error ("unhandled register size: %d",
183 			    i386_st_collect_regmap[i].size);
184 	  }
185       }
186 }
187 
188 #endif /* HAVE_UST */
189 
190 
191 /* This is only needed because reg-i386-linux-lib.o references it.  We
192    may use it proper at some point.  */
193 const char *gdbserver_xmltarget;
194 
195 /* Attempt to allocate memory for trampolines in the first 64 KiB of
196    memory to enable smaller jump patches.  */
197 
198 static void
199 initialize_fast_tracepoint_trampoline_buffer (void)
200 {
201   const CORE_ADDR buffer_end = 64 * 1024;
202   /* Ensure that the buffer will be at least 1 KiB in size, which is
203      enough space for over 200 fast tracepoints.  */
204   const int min_buffer_size = 1024;
205   char buf[IPA_BUFSIZ];
206   CORE_ADDR mmap_min_addr = buffer_end + 1;
207   ULONGEST buffer_size;
208   FILE *f = fopen ("/proc/sys/vm/mmap_min_addr", "r");
209 
210   if (!f)
211     {
212       snprintf (buf, sizeof (buf), "mmap_min_addr open failed: %s",
213 		safe_strerror (errno));
214       set_trampoline_buffer_space (0, 0, buf);
215       return;
216     }
217 
218   if (fgets (buf, IPA_BUFSIZ, f))
219     sscanf (buf, "%llu", &mmap_min_addr);
220 
221   fclose (f);
222 
223   buffer_size = buffer_end - mmap_min_addr;
224 
225   if (buffer_size >= min_buffer_size)
226     {
227       if (mmap ((void *) (uintptr_t) mmap_min_addr, buffer_size,
228 		PROT_READ | PROT_EXEC | PROT_WRITE,
229 		MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
230 		-1, 0)
231 	  != MAP_FAILED)
232 	set_trampoline_buffer_space (mmap_min_addr, buffer_end, NULL);
233       else
234 	{
235 	  snprintf (buf, IPA_BUFSIZ, "low-64K-buffer mmap() failed: %s",
236 		    safe_strerror (errno));
237 	  set_trampoline_buffer_space (0, 0, buf);
238 	}
239     }
240   else
241     {
242       snprintf (buf, IPA_BUFSIZ, "mmap_min_addr is %d, must be %d or less",
243 		(int) mmap_min_addr, (int) buffer_end - min_buffer_size);
244       set_trampoline_buffer_space (0, 0, buf);
245     }
246 }
247 
248 /* Map the tdesc index to xcr0 mask.  */
249 static uint64_t idx2mask[X86_TDESC_LAST] = {
250   X86_XSTATE_X87_MASK,
251   X86_XSTATE_SSE_MASK,
252   X86_XSTATE_AVX_MASK,
253   X86_XSTATE_MPX_MASK,
254   X86_XSTATE_AVX_MPX_MASK,
255   X86_XSTATE_AVX_AVX512_MASK,
256   X86_XSTATE_AVX_MPX_AVX512_PKU_MASK,
257 };
258 
259 /* Return target_desc to use for IPA, given the tdesc index passed by
260    gdbserver.  */
261 
262 const struct target_desc *
263 get_ipa_tdesc (int idx)
264 {
265   if (idx >= X86_TDESC_LAST)
266     {
267       internal_error ("unknown ipa tdesc index: %d", idx);
268     }
269   return i386_linux_read_description (idx2mask[idx]);
270 }
271 
272 /* Allocate buffer for the jump pads.  On i386, we can reach an arbitrary
273    address with a jump instruction, so just allocate normally.  */
274 
275 void *
276 alloc_jump_pad_buffer (size_t size)
277 {
278   void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
279 		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
280 
281   if (res == MAP_FAILED)
282     return NULL;
283 
284   return res;
285 }
286 
287 void
288 initialize_low_tracepoint (void)
289 {
290   initialize_fast_tracepoint_trampoline_buffer ();
291   for (auto i = 0; i < X86_TDESC_LAST; i++)
292     i386_linux_read_description (idx2mask[i]);
293 }
294