123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /* GNU/Linux/x86-64 specific low level interface, for the in-process
- agent library for GDB.
- Copyright (C) 2010-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #include "server.h"
- #include <sys/mman.h>
- #include "tracepoint.h"
- #include "linux-x86-tdesc.h"
- #include "gdbsupport/x86-xstate.h"
- /* Defined in auto-generated file amd64-linux.c. */
- void init_registers_amd64_linux (void);
- extern const struct target_desc *tdesc_amd64_linux;
- /* fast tracepoints collect registers. */
- #define FT_CR_RIP 0
- #define FT_CR_EFLAGS 1
- #define FT_CR_R8 2
- #define FT_CR_R9 3
- #define FT_CR_R10 4
- #define FT_CR_R11 5
- #define FT_CR_R12 6
- #define FT_CR_R13 7
- #define FT_CR_R14 8
- #define FT_CR_R15 9
- #define FT_CR_RAX 10
- #define FT_CR_RBX 11
- #define FT_CR_RCX 12
- #define FT_CR_RDX 13
- #define FT_CR_RSI 14
- #define FT_CR_RDI 15
- #define FT_CR_RBP 16
- #define FT_CR_RSP 17
- static const int x86_64_ft_collect_regmap[] = {
- FT_CR_RAX * 8, FT_CR_RBX * 8, FT_CR_RCX * 8, FT_CR_RDX * 8,
- FT_CR_RSI * 8, FT_CR_RDI * 8, FT_CR_RBP * 8, FT_CR_RSP * 8,
- FT_CR_R8 * 8, FT_CR_R9 * 8, FT_CR_R10 * 8, FT_CR_R11 * 8,
- FT_CR_R12 * 8, FT_CR_R13 * 8, FT_CR_R14 * 8, FT_CR_R15 * 8,
- FT_CR_RIP * 8, FT_CR_EFLAGS * 8
- };
- #define X86_64_NUM_FT_COLLECT_GREGS \
- (sizeof (x86_64_ft_collect_regmap) / sizeof(x86_64_ft_collect_regmap[0]))
- void
- supply_fast_tracepoint_registers (struct regcache *regcache,
- const unsigned char *buf)
- {
- int i;
- for (i = 0; i < X86_64_NUM_FT_COLLECT_GREGS; i++)
- supply_register (regcache, i,
- ((char *) buf) + x86_64_ft_collect_regmap[i]);
- }
- ULONGEST
- get_raw_reg (const unsigned char *raw_regs, int regnum)
- {
- if (regnum >= X86_64_NUM_FT_COLLECT_GREGS)
- return 0;
- return *(ULONGEST *) (raw_regs + x86_64_ft_collect_regmap[regnum]);
- }
- #ifdef HAVE_UST
- #include <ust/processor.h>
- /* "struct registers" is the UST object type holding the registers at
- the time of the static tracepoint marker call. This doesn't
- contain RIP, but we know what it must have been (the marker
- address). */
- #define ST_REGENTRY(REG) \
- { \
- offsetof (struct registers, REG), \
- sizeof (((struct registers *) NULL)->REG) \
- }
- static struct
- {
- int offset;
- int size;
- } x86_64_st_collect_regmap[] =
- {
- ST_REGENTRY(rax),
- ST_REGENTRY(rbx),
- ST_REGENTRY(rcx),
- ST_REGENTRY(rdx),
- ST_REGENTRY(rsi),
- ST_REGENTRY(rdi),
- ST_REGENTRY(rbp),
- ST_REGENTRY(rsp),
- ST_REGENTRY(r8),
- ST_REGENTRY(r9),
- ST_REGENTRY(r10),
- ST_REGENTRY(r11),
- ST_REGENTRY(r12),
- ST_REGENTRY(r13),
- ST_REGENTRY(r14),
- ST_REGENTRY(r15),
- { -1, 0 },
- ST_REGENTRY(rflags),
- ST_REGENTRY(cs),
- ST_REGENTRY(ss),
- };
- #define X86_64_NUM_ST_COLLECT_GREGS \
- (sizeof (x86_64_st_collect_regmap) / sizeof (x86_64_st_collect_regmap[0]))
- /* GDB's RIP register number. */
- #define AMD64_RIP_REGNUM 16
- void
- supply_static_tracepoint_registers (struct regcache *regcache,
- const unsigned char *buf,
- CORE_ADDR pc)
- {
- int i;
- unsigned long newpc = pc;
- supply_register (regcache, AMD64_RIP_REGNUM, &newpc);
- for (i = 0; i < X86_64_NUM_ST_COLLECT_GREGS; i++)
- if (x86_64_st_collect_regmap[i].offset != -1)
- {
- switch (x86_64_st_collect_regmap[i].size)
- {
- case 8:
- supply_register (regcache, i,
- ((char *) buf)
- + x86_64_st_collect_regmap[i].offset);
- break;
- case 2:
- {
- unsigned long reg
- = * (short *) (((char *) buf)
- + x86_64_st_collect_regmap[i].offset);
- reg &= 0xffff;
- supply_register (regcache, i, ®);
- }
- break;
- default:
- internal_error (__FILE__, __LINE__,
- "unhandled register size: %d",
- x86_64_st_collect_regmap[i].size);
- break;
- }
- }
- }
- #endif /* HAVE_UST */
- #if !defined __ILP32__
- /* Map the tdesc index to xcr0 mask. */
- static uint64_t idx2mask[X86_TDESC_LAST] = {
- X86_XSTATE_X87_MASK,
- X86_XSTATE_SSE_MASK,
- X86_XSTATE_AVX_MASK,
- X86_XSTATE_MPX_MASK,
- X86_XSTATE_AVX_MPX_MASK,
- X86_XSTATE_AVX_AVX512_MASK,
- X86_XSTATE_AVX_MPX_AVX512_PKU_MASK,
- };
- #endif
- /* Return target_desc to use for IPA, given the tdesc index passed by
- gdbserver. */
- const struct target_desc *
- get_ipa_tdesc (int idx)
- {
- if (idx >= X86_TDESC_LAST)
- {
- internal_error (__FILE__, __LINE__,
- "unknown ipa tdesc index: %d", idx);
- }
- #if defined __ILP32__
- switch (idx)
- {
- case X86_TDESC_SSE:
- return amd64_linux_read_description (X86_XSTATE_SSE_MASK, true);
- case X86_TDESC_AVX:
- return amd64_linux_read_description (X86_XSTATE_AVX_MASK, true);
- case X86_TDESC_AVX_AVX512:
- return amd64_linux_read_description (X86_XSTATE_AVX_AVX512_MASK, true);
- default:
- break;
- }
- #else
- return amd64_linux_read_description (idx2mask[idx], false);
- #endif
- internal_error (__FILE__, __LINE__,
- "unknown ipa tdesc index: %d", idx);
- }
- /* Allocate buffer for the jump pads. The branch instruction has a
- reach of +/- 31-bit, and the executable is loaded at low addresses.
- 64-bit: Use MAP_32BIT to allocate in the first 2GB. Shared
- libraries, being allocated at the top, are unfortunately out of
- luck.
- x32: Since MAP_32BIT is 64-bit only, do the placement manually.
- Try allocating at '0x80000000 - SIZE' initially, decreasing until
- we hit a free area. This ensures the executable is fully covered,
- and is as close as possible to the shared libraries, which are
- usually mapped at the top of the first 4GB of the address space.
- */
- void *
- alloc_jump_pad_buffer (size_t size)
- {
- #if __ILP32__
- uintptr_t addr;
- int pagesize;
- pagesize = sysconf (_SC_PAGE_SIZE);
- if (pagesize == -1)
- perror_with_name ("sysconf");
- addr = 0x80000000 - size;
- /* size should already be page-aligned, but this can't hurt. */
- addr &= ~(pagesize - 1);
- /* Search for a free area. If we hit 0, we're out of luck. */
- for (; addr; addr -= pagesize)
- {
- void *res;
- /* No MAP_FIXED - we don't want to zap someone's mapping. */
- res = mmap ((void *) addr, size,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- /* If we got what we wanted, return. */
- if ((uintptr_t) res == addr)
- return res;
- /* If we got a mapping, but at a wrong address, undo it. */
- if (res != MAP_FAILED)
- munmap (res, size);
- }
- return NULL;
- #else
- void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
- if (res == MAP_FAILED)
- return NULL;
- return res;
- #endif
- }
- void
- initialize_low_tracepoint (void)
- {
- #if defined __ILP32__
- amd64_linux_read_description (X86_XSTATE_SSE_MASK, true);
- amd64_linux_read_description (X86_XSTATE_AVX_MASK, true);
- amd64_linux_read_description (X86_XSTATE_AVX_AVX512_MASK, true);
- #else
- for (auto i = 0; i < X86_TDESC_LAST; i++)
- amd64_linux_read_description (idx2mask[i], false);
- #endif
- }
|