X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fgdbserver%2Flinux-i386-ipa.c;h=68d65ac92a4439b9d7267b36bb686a2271a7b92b;hb=7c3a12caf5ea2c9055312e9c3c286aa69b170ecc;hp=69f67495a7e5e129f428e54f07cc107e51ba0c16;hpb=fa593d66d5696018bc8fb166f9e2a960d484ccd0;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c index 69f67495a7..68d65ac92a 100644 --- a/gdb/gdbserver/linux-i386-ipa.c +++ b/gdb/gdbserver/linux-i386-ipa.c @@ -1,7 +1,7 @@ /* GNU/Linux/x86 specific low level interface, for the in-process agent library for GDB. - Copyright (C) 2010 Free Software Foundation, Inc. + Copyright (C) 2010-2013 Free Software Foundation, Inc. This file is part of GDB. @@ -19,6 +19,9 @@ along with this program. If not, see . */ #include "server.h" +#include +#include +#include "tracepoint.h" /* GDB register numbers. */ @@ -47,6 +50,7 @@ enum i386_gdb_regnum /* Defined in auto-generated file i386-linux.c. */ void init_registers_i386_linux (void); +extern const struct target_desc *tdesc_i386_linux; #define FT_CR_EAX 15 #define FT_CR_ECX 14 @@ -95,12 +99,159 @@ supply_fast_tracepoint_registers (struct regcache *regcache, } } +ULONGEST __attribute__ ((visibility("default"), used)) +gdb_agent_get_raw_reg (unsigned char *raw_regs, int regnum) +{ + /* This should maybe be allowed to return an error code, or perhaps + better, have the emit_reg detect this, and emit a constant zero, + or something. */ + + if (regnum > i386_num_regs) + return 0; + else if (regnum >= I386_CS_REGNUM && regnum <= I386_GS_REGNUM) + return *(short *) (raw_regs + i386_ft_collect_regmap[regnum]); + else + return *(int *) (raw_regs + i386_ft_collect_regmap[regnum]); +} + +#ifdef HAVE_UST + +#include + +/* "struct registers" is the UST object type holding the registers at + the time of the static tracepoint marker call. This doesn't + contain EIP, 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; +} i386_st_collect_regmap[] = + { + ST_REGENTRY(eax), + ST_REGENTRY(ecx), + ST_REGENTRY(edx), + ST_REGENTRY(ebx), + ST_REGENTRY(esp), + ST_REGENTRY(ebp), + ST_REGENTRY(esi), + ST_REGENTRY(edi), + { -1, 0 }, /* eip */ + ST_REGENTRY(eflags), + ST_REGENTRY(cs), + ST_REGENTRY(ss), + }; + +#define i386_NUM_ST_COLLECT_GREGS \ + (sizeof (i386_st_collect_regmap) / sizeof (i386_st_collect_regmap[0])) + +void +supply_static_tracepoint_registers (struct regcache *regcache, + const unsigned char *buf, + CORE_ADDR pc) +{ + int i; + unsigned int newpc = pc; + + supply_register (regcache, I386_EIP_REGNUM, &newpc); + + for (i = 0; i < i386_NUM_ST_COLLECT_GREGS; i++) + if (i386_st_collect_regmap[i].offset != -1) + { + switch (i386_st_collect_regmap[i].size) + { + case 4: + supply_register (regcache, i, + ((char *) buf) + + i386_st_collect_regmap[i].offset); + break; + case 2: + { + unsigned long reg + = * (short *) (((char *) buf) + + i386_st_collect_regmap[i].offset); + reg &= 0xffff; + supply_register (regcache, i, ®); + } + break; + default: + internal_error (__FILE__, __LINE__, "unhandled register size: %d", + i386_st_collect_regmap[i].size); + } + } +} + +#endif /* HAVE_UST */ + + /* This is only needed because reg-i386-linux-lib.o references it. We may use it proper at some point. */ const char *gdbserver_xmltarget; +/* Attempt to allocate memory for trampolines in the first 64 KiB of + memory to enable smaller jump patches. */ + +static void +initialize_fast_tracepoint_trampoline_buffer (void) +{ + const CORE_ADDR buffer_end = 64 * 1024; + /* Ensure that the buffer will be at least 1 KiB in size, which is + enough space for over 200 fast tracepoints. */ + const int min_buffer_size = 1024; + char buf[IPA_BUFSIZ]; + CORE_ADDR mmap_min_addr = buffer_end + 1; + ULONGEST buffer_size; + FILE *f = fopen ("/proc/sys/vm/mmap_min_addr", "r"); + + if (!f) + { + snprintf (buf, sizeof (buf), "mmap_min_addr open failed: %s", + strerror (errno)); + set_trampoline_buffer_space (0, 0, buf); + return; + } + + if (fgets (buf, IPA_BUFSIZ, f)) + sscanf (buf, "%llu", &mmap_min_addr); + + fclose (f); + + buffer_size = buffer_end - mmap_min_addr; + + if (buffer_size >= min_buffer_size) + { + if (mmap ((void *) (uintptr_t) mmap_min_addr, buffer_size, + PROT_READ | PROT_EXEC | PROT_WRITE, + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0) + != MAP_FAILED) + set_trampoline_buffer_space (mmap_min_addr, buffer_end, NULL); + else + { + snprintf (buf, IPA_BUFSIZ, "low-64K-buffer mmap() failed: %s", + strerror (errno)); + set_trampoline_buffer_space (0, 0, buf); + } + } + else + { + snprintf (buf, IPA_BUFSIZ, "mmap_min_addr is %d, must be %d or less", + (int) mmap_min_addr, (int) buffer_end - min_buffer_size); + set_trampoline_buffer_space (0, 0, buf); + } +} + void initialize_low_tracepoint (void) { init_registers_i386_linux (); + ipa_tdesc = tdesc_i386_linux; + initialize_fast_tracepoint_trampoline_buffer (); }