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