binutils-gdb/gdb/gdbserver/linux-aarch64-ipa.c
Pierre Langlois bb903df05b Add support for fast tracepoints
This patch adds support for fast tracepoints for aarch64-linux.  With this
implementation, a tracepoint can only be placed in a +/- 128MB range of
the jump pad.  This is due to the unconditional branch instruction
being limited to a (26 bit << 2) offset from the current PC.

Three target operations are implemented:

- target_install_fast_tracepoint_jump_pad

Building the jump pad the biggest change of this patch.  We need to add
functions to emit all instructions needed to save and restore the
current state when the tracepoint is hit.  As well as implementing a
lock and creating a collecting_t object identifying the current thread.

Steps performed by the jump pad:

  * Save the current state on the stack.
  * Push a collecting_t object on the stack.  We read the special
  tpidr_el0 system register to get the thread ID.
  * Spin-lock on the shared memory location of all tracing threads.  We
  write the address of our collecting_t object there once we have the
  lock.
  * Call gdb_collect.
  * Release the lock.
  * Restore the state.

  * Execute the replaced instruction which will have been relocated.
  * Jump back to the program.

- target_get_thread_area

As implemented in ps_get_thread_area, target_get_thread_area uses ptrace
to fetch the NT_ARM_TLS register.  At the architecture level, NT_ARM_TLS
represents the tpidr_el0 system register.

So this ptrace call (if lwpid is the current thread):
~~~
ptrace (PTRACE_GETREGSET, lwpid, NT_ARM_TLS, &iovec);
~~~

Is equivalent to the following instruction:
~~~
msr x0, tpidr_el0
~~~

This instruction is used when creating the collecting_t object that
GDBserver can read to know if a given thread is currently tracing.

So target_get_thread_area must get the same thread IDs as what the jump
pad writes into its collecting_t object.

- target_get_min_fast_tracepoint_insn_len

This just returns 4.

gdb/gdbserver/ChangeLog:

	* Makefile.in (linux-aarch64-ipa.o, aarch64-ipa.o): New rules.
	* configure.srv (aarch64*-*-linux*): Add linux-aarch64-ipa.o and
	aarch64-ipa.o.
	* linux-aarch64-ipa.c: New file.
	* linux-aarch64-low.c: Include arch/aarch64-insn.h, inttypes.h
	and endian.h.
	(aarch64_get_thread_area): New target method.
	(extract_signed_bitfield): New helper function.
	(aarch64_decode_ldr_literal): New function.
	(enum aarch64_opcodes): New enum.
	(struct aarch64_register): New struct.
	(struct aarch64_operand): New struct.
	(x0): New static global.
	(x1): Likewise.
	(x2): Likewise.
	(x3): Likewise.
	(x4): Likewise.
	(w2): Likewise.
	(ip0): Likewise.
	(sp): Likewise.
	(xzr): Likewise.
	(aarch64_register): New helper function.
	(register_operand): Likewise.
	(immediate_operand): Likewise.
	(struct aarch64_memory_operand): New struct.
	(offset_memory_operand): New helper function.
	(preindex_memory_operand): Likewise.
	(enum aarch64_system_control_registers): New enum.
	(ENCODE): New macro.
	(emit_insn): New helper function.
	(emit_b): New function.
	(emit_bcond): Likewise.
	(emit_cb): Likewise.
	(emit_tb): Likewise.
	(emit_blr): Likewise.
	(emit_stp): Likewise.
	(emit_ldp_q_offset): Likewise.
	(emit_stp_q_offset): Likewise.
	(emit_load_store): Likewise.
	(emit_ldr): Likewise.
	(emit_ldrsw): Likewise.
	(emit_str): Likewise.
	(emit_ldaxr): Likewise.
	(emit_stxr): Likewise.
	(emit_stlr): Likewise.
	(emit_data_processing_reg): Likewise.
	(emit_data_processing): Likewise.
	(emit_add): Likewise.
	(emit_sub): Likewise.
	(emit_mov): Likewise.
	(emit_movk): Likewise.
	(emit_mov_addr): Likewise.
	(emit_mrs): Likewise.
	(emit_msr): Likewise.
	(emit_sevl): Likewise.
	(emit_wfe): Likewise.
	(append_insns): Likewise.
	(can_encode_int32_in): New helper function.
	(aarch64_relocate_instruction): New function.
	(aarch64_install_fast_tracepoint_jump_pad): Likewise.
	(aarch64_get_min_fast_tracepoint_insn_len): Likewise.
	(struct linux_target_ops): Install aarch64_get_thread_area,
	aarch64_install_fast_tracepoint_jump_pad and
	aarch64_get_min_fast_tracepoint_insn_len.
2015-09-21 15:01:04 +01:00

152 lines
3.5 KiB
C

/* GNU/Linux/AArch64 specific low level interface, for the in-process
agent library for GDB.
Copyright (C) 2015 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 "tracepoint.h"
/* Defined in auto-generated file aarch64.c. */
void init_registers_aarch64 (void);
extern const struct target_desc *tdesc_aarch64;
/* Each register saved by the jump pad is in a 16 byte cell. */
#define FT_CR_SIZE 16
#define FT_CR_FPCR 0
#define FT_CR_FPSR 1
#define FT_CR_CPSR 2
#define FT_CR_PC 3
#define FT_CR_SP 4
#define FT_CR_X0 5
#define FT_CR_GPR(n) (FT_CR_X0 + (n))
#define FT_CR_FPR(n) (FT_CR_GPR (31) + (n))
/* Mapping between registers collected by the jump pad and GDB's register
array layout used by regcache.
See linux-aarch64-low.c (aarch64_install_fast_tracepoint_jump_pad) for
more details. */
static const int aarch64_ft_collect_regmap[] = {
FT_CR_GPR (0),
FT_CR_GPR (1),
FT_CR_GPR (2),
FT_CR_GPR (3),
FT_CR_GPR (4),
FT_CR_GPR (5),
FT_CR_GPR (6),
FT_CR_GPR (7),
FT_CR_GPR (8),
FT_CR_GPR (9),
FT_CR_GPR (10),
FT_CR_GPR (11),
FT_CR_GPR (12),
FT_CR_GPR (13),
FT_CR_GPR (14),
FT_CR_GPR (15),
FT_CR_GPR (16),
FT_CR_GPR (17),
FT_CR_GPR (18),
FT_CR_GPR (19),
FT_CR_GPR (20),
FT_CR_GPR (21),
FT_CR_GPR (22),
FT_CR_GPR (23),
FT_CR_GPR (24),
FT_CR_GPR (25),
FT_CR_GPR (26),
FT_CR_GPR (27),
FT_CR_GPR (28),
/* FP */
FT_CR_GPR (29),
/* LR */
FT_CR_GPR (30),
FT_CR_SP,
FT_CR_PC,
FT_CR_CPSR,
FT_CR_FPR (0),
FT_CR_FPR (1),
FT_CR_FPR (2),
FT_CR_FPR (3),
FT_CR_FPR (4),
FT_CR_FPR (5),
FT_CR_FPR (6),
FT_CR_FPR (7),
FT_CR_FPR (8),
FT_CR_FPR (9),
FT_CR_FPR (10),
FT_CR_FPR (11),
FT_CR_FPR (12),
FT_CR_FPR (13),
FT_CR_FPR (14),
FT_CR_FPR (15),
FT_CR_FPR (16),
FT_CR_FPR (17),
FT_CR_FPR (18),
FT_CR_FPR (19),
FT_CR_FPR (20),
FT_CR_FPR (21),
FT_CR_FPR (22),
FT_CR_FPR (23),
FT_CR_FPR (24),
FT_CR_FPR (25),
FT_CR_FPR (26),
FT_CR_FPR (27),
FT_CR_FPR (28),
FT_CR_FPR (29),
FT_CR_FPR (30),
FT_CR_FPR (31),
FT_CR_FPSR,
FT_CR_FPCR
};
#define AARCH64_NUM_FT_COLLECT_GREGS \
(sizeof (aarch64_ft_collect_regmap) / sizeof(aarch64_ft_collect_regmap[0]))
/* Fill in REGCACHE with registers saved by the jump pad in BUF. */
void
supply_fast_tracepoint_registers (struct regcache *regcache,
const unsigned char *buf)
{
int i;
for (i = 0; i < AARCH64_NUM_FT_COLLECT_GREGS; i++)
supply_register (regcache, i,
((char *) buf)
+ (aarch64_ft_collect_regmap[i] * FT_CR_SIZE));
}
IP_AGENT_EXPORT_FUNC ULONGEST
gdb_agent_get_raw_reg (const unsigned char *raw_regs, int regnum)
{
if (regnum >= AARCH64_NUM_FT_COLLECT_GREGS)
return 0;
return *(ULONGEST *) (raw_regs
+ aarch64_ft_collect_regmap[regnum] * FT_CR_SIZE);
}
void
initialize_low_tracepoint (void)
{
init_registers_aarch64 ();
ipa_tdesc = tdesc_aarch64;
}