Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.462 diff -p -r1.462 NEWS *** NEWS 28 Oct 2011 14:48:36 -0000 1.462 --- NEWS 29 Oct 2011 00:37:56 -0000 *************** *** 13,18 **** --- 13,23 ---- watchpoints are slower than real hardware watchpoints but are significantly faster than gdb software watchpoints. + qTMinFTPILen + + Query the minimum length of instruction at which a fast tracepoint may + be placed. + * Python scripting ** The register_pretty_printer function in module gdb.printing now takes Index: i386-tdep.c =================================================================== RCS file: /cvs/src/src/gdb/i386-tdep.c,v retrieving revision 1.339 diff -p -r1.339 i386-tdep.c *** i386-tdep.c 11 Oct 2011 19:08:58 -0000 1.339 --- i386-tdep.c 29 Oct 2011 00:37:56 -0000 *************** static const int i386_record_regmap[] = *** 7109,7118 **** }; /* Check that the given address appears suitable for a fast ! tracepoint, which on x86 means that we need an instruction of at least 5 bytes, so that we can overwrite it with a 4-byte-offset jump and not have to worry about program jumps to an address in the ! middle of the tracepoint jump. Returns 1 if OK, and writes a size of instruction to replace, and 0 if not, plus an explanatory string. */ --- 7109,7120 ---- }; /* Check that the given address appears suitable for a fast ! tracepoint, which on x86-64 means that we need an instruction of at least 5 bytes, so that we can overwrite it with a 4-byte-offset jump and not have to worry about program jumps to an address in the ! middle of the tracepoint jump. On x86, it may be possible to use ! 4-byte jumps with a 2-byte offset to a trampoline located in the ! bottom 64 KiB of memory. Returns 1 if OK, and writes a size of instruction to replace, and 0 if not, plus an explanatory string. */ *************** i386_fast_tracepoint_valid_at (struct gd *** 7123,7132 **** int len, jumplen; static struct ui_file *gdb_null = NULL; ! /* This is based on the target agent using a 4-byte relative jump. ! Alternate future possibilities include 8-byte offset for x86-84, ! or 3-byte jumps if the program has trampoline space close by. */ ! jumplen = 5; /* Dummy file descriptor for the disassembler. */ if (!gdb_null) --- 7125,7150 ---- int len, jumplen; static struct ui_file *gdb_null = NULL; ! /* Ask the target for the minimum instruction length supported. */ ! jumplen = target_get_min_fast_tracepoint_insn_len (); ! ! if (jumplen < 0) ! { ! /* If the target does not support the get_min_fast_tracepoint_insn_len ! operation, assume that fast tracepoints will always be implemented ! using 4-byte relative jumps on both x86 and x86-64. */ ! jumplen = 5; ! } ! else if (jumplen == 0) ! { ! /* If the target does support get_min_fast_tracepoint_insn_len but ! returns zero, then the IPA has not loaded yet. In this case, ! we optimistically assume that truncated 2-byte relative jumps ! will be available on x86, and compensate later if this assumption ! turns out to be incorrect. On x86-64 architectures, 4-byte relative ! jumps will always be used. */ ! jumplen = (register_size (gdbarch, 0) == 8) ? 5 : 4; ! } /* Dummy file descriptor for the disassembler. */ if (!gdb_null) *************** i386_fast_tracepoint_valid_at (struct gd *** 7134,7139 **** --- 7152,7160 ---- /* Check for fit. */ len = gdb_print_insn (gdbarch, addr, gdb_null, NULL); + if (isize) + *isize = len; + if (len < jumplen) { /* Return a bit of target-specific detail to add to the caller's *************** i386_fast_tracepoint_valid_at (struct gd *** 7144,7155 **** len, jumplen); return 0; } ! ! if (isize) ! *isize = len; ! if (msg) ! *msg = NULL; ! return 1; } static int --- 7165,7176 ---- len, jumplen); return 0; } ! else ! { ! if (msg) ! *msg = NULL; ! return 1; ! } } static int Index: remote.c =================================================================== RCS file: /cvs/src/src/gdb/remote.c,v retrieving revision 1.465 diff -p -r1.465 remote.c *** remote.c 13 Oct 2011 13:15:16 -0000 1.465 --- remote.c 29 Oct 2011 00:37:56 -0000 *************** remote_write_bytes_aux (const char *head *** 6338,6344 **** if (todo <= 0) internal_error (__FILE__, __LINE__, ! _("minumum packet size too small to write data")); /* If we already need another packet, then try to align the end of this packet to a useful boundary. */ --- 6338,6344 ---- if (todo <= 0) internal_error (__FILE__, __LINE__, ! _("minimum packet size too small to write data")); /* If we already need another packet, then try to align the end of this packet to a useful boundary. */ *************** remote_download_tracepoint (struct break *** 9859,9869 **** tpaddr, &isize, NULL)) sprintf (buf + strlen (buf), ":F%x", isize); else ! /* If it passed validation at definition but fails now, ! something is very wrong. */ ! internal_error (__FILE__, __LINE__, ! _("Fast tracepoint not " ! "valid during download")); } else /* Fast tracepoints are functionally identical to regular --- 9859,9868 ---- tpaddr, &isize, NULL)) sprintf (buf + strlen (buf), ":F%x", isize); else ! warning (_("Target does not support fast tracepoints at " ! "%d-byte long instructions, downloading %d as " ! "regular tracepoint."), ! isize, b->number); } else /* Fast tracepoints are functionally identical to regular *************** remote_traceframe_info (void) *** 10390,10395 **** --- 10389,10419 ---- return NULL; } + /* Handle the qTMinFTPILen packet. Returns the minimum length of instruction + on which a fast tracepoint may be placed. Returns -1 if the packet is not + supported, and 0 if the minimum instruction length is unknown. */ + + static int + remote_get_min_fast_tracepoint_insn_len (void) + { + struct remote_state *rs = get_remote_state (); + char *reply; + + sprintf (rs->buf, "qTMinFTPILen"); + putpkt (rs->buf); + reply = remote_get_noisy_reply (&target_buf, &target_buf_size); + if (*reply == '\0') + return -1; + else + { + ULONGEST min_insn_len; + + unpack_varlen_hex (reply, &min_insn_len); + + return (int) min_insn_len; + } + } + static void init_remote_ops (void) { *************** Specify the serial device it is connecte *** 10477,10482 **** --- 10501,10507 ---- remote_ops.to_upload_trace_state_variables = remote_upload_trace_state_variables; remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data; + remote_ops.to_get_min_fast_tracepoint_insn_len = remote_get_min_fast_tracepoint_insn_len; remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing; remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer; remote_ops.to_core_of_thread = remote_core_of_thread; Index: target.c =================================================================== RCS file: /cvs/src/src/gdb/target.c,v retrieving revision 1.286 diff -p -r1.286 target.c *** target.c 7 Oct 2011 12:06:46 -0000 1.286 --- target.c 29 Oct 2011 00:37:56 -0000 *************** update_current_target (void) *** 687,692 **** --- 687,693 ---- INHERIT (to_upload_tracepoints, t); INHERIT (to_upload_trace_state_variables, t); INHERIT (to_get_raw_trace_data, t); + INHERIT (to_get_min_fast_tracepoint_insn_len, t); INHERIT (to_set_disconnected_tracing, t); INHERIT (to_set_circular_trace_buffer, t); INHERIT (to_get_tib_address, t); *************** update_current_target (void) *** 885,890 **** --- 886,894 ---- de_fault (to_get_raw_trace_data, (LONGEST (*) (gdb_byte *, ULONGEST, LONGEST)) tcomplain); + de_fault (to_get_min_fast_tracepoint_insn_len, + (int (*) (void)) + return_minus_one); de_fault (to_set_disconnected_tracing, (void (*) (int)) target_ignore); Index: target.h =================================================================== RCS file: /cvs/src/src/gdb/target.h,v retrieving revision 1.214 diff -p -r1.214 target.h *** target.h 28 Oct 2011 18:29:59 -0000 1.214 --- target.h 29 Oct 2011 00:37:56 -0000 *************** struct target_ops *** 731,736 **** --- 731,742 ---- LONGEST (*to_get_raw_trace_data) (gdb_byte *buf, ULONGEST offset, LONGEST len); + /* Get the minimum length of instruction on which a fast tracepoint + may be set on the target. If this operation is unsupported, + return -1. If for some reason the minimum length cannot be + determined, return 0. */ + int (*to_get_min_fast_tracepoint_insn_len) (void); + /* Set the target's tracing behavior in response to unexpected disconnection - set VAL to 1 to keep tracing, 0 to stop. */ void (*to_set_disconnected_tracing) (int val); *************** extern int target_search_memory (CORE_AD *** 1510,1515 **** --- 1516,1524 ---- #define target_get_raw_trace_data(buf,offset,len) \ (*current_target.to_get_raw_trace_data) ((buf), (offset), (len)) + #define target_get_min_fast_tracepoint_insn_len() \ + (*current_target.to_get_min_fast_tracepoint_insn_len) () + #define target_set_disconnected_tracing(val) \ (*current_target.to_set_disconnected_tracing) (val) Index: gdbserver/linux-i386-ipa.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-i386-ipa.c,v retrieving revision 1.5 diff -p -r1.5 linux-i386-ipa.c *** gdbserver/linux-i386-ipa.c 16 May 2011 15:59:45 -0000 1.5 --- gdbserver/linux-i386-ipa.c 29 Oct 2011 00:37:56 -0000 *************** *** 19,24 **** --- 19,26 ---- along with this program. If not, see . */ #include "server.h" + #include + #include /* GDB register numbers. */ *************** supply_static_tracepoint_registers (stru *** 191,198 **** --- 193,247 ---- 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; + char buf[100]; + 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, 100, f)) + sscanf (buf, "%llu", &mmap_min_addr); + + fclose (f); + + buffer_size = buffer_end - mmap_min_addr; + + /* Ensure that the buffer will be at least 1 KiB in size (i.e. enough + space for over 200 fast tracepoints). */ + if (buffer_size >= 1024) + { + 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, 99, "low-64K-buffer mmap() failed: %s", + strerror (errno)); + set_trampoline_buffer_space (0, 0, buf); + } + } + } + void initialize_low_tracepoint (void) { init_registers_i386_linux (); + initialize_fast_tracepoint_trampoline_buffer (); } Index: gdbserver/linux-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v retrieving revision 1.178 diff -p -r1.178 linux-low.c *** gdbserver/linux-low.c 7 Oct 2011 12:06:48 -0000 1.178 --- gdbserver/linux-low.c 29 Oct 2011 00:37:57 -0000 *************** linux_install_fast_tracepoint_jump_pad ( *** 4933,4947 **** CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end) { return (*the_low_target.install_fast_tracepoint_jump_pad) (tpoint, tpaddr, collector, lockaddr, orig_size, ! jump_entry, jjump_pad_insn, jjump_pad_insn_size, ! adjusted_insn_addr, adjusted_insn_addr_end); } static struct emit_ops * --- 4933,4952 ---- CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end, ! char *err) { return (*the_low_target.install_fast_tracepoint_jump_pad) (tpoint, tpaddr, collector, lockaddr, orig_size, ! jump_entry, trampoline, trampoline_size, ! jjump_pad_insn, jjump_pad_insn_size, ! adjusted_insn_addr, adjusted_insn_addr_end, ! err); } static struct emit_ops * *************** linux_emit_ops (void) *** 4953,4958 **** --- 4958,4969 ---- return NULL; } + static int + linux_get_min_fast_tracepoint_insn_len (void) + { + return (*the_low_target.get_min_fast_tracepoint_insn_len) (); + } + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, *************** static struct target_ops linux_target_op *** 5014,5019 **** --- 5025,5031 ---- linux_install_fast_tracepoint_jump_pad, linux_emit_ops, linux_supports_disable_randomization, + linux_get_min_fast_tracepoint_insn_len, }; static void Index: gdbserver/linux-low.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v retrieving revision 1.47 diff -p -r1.47 linux-low.h *** gdbserver/linux-low.h 1 Jan 2011 15:33:24 -0000 1.47 --- gdbserver/linux-low.h 29 Oct 2011 00:37:57 -0000 *************** struct linux_target_ops *** 132,145 **** CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end); /* Return the bytecode operations vector for the current inferior. Returns NULL if bytecode compilation is not supported. */ struct emit_ops *(*emit_ops) (void); }; extern struct linux_target_ops the_low_target; --- 132,153 ---- CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end, ! char *err); /* Return the bytecode operations vector for the current inferior. Returns NULL if bytecode compilation is not supported. */ struct emit_ops *(*emit_ops) (void); + + /* Return the minimum length of an instruction that can be safely overwritten + for use as a fast tracepoint. */ + int (*get_min_fast_tracepoint_insn_len) (void); + }; extern struct linux_target_ops the_low_target; Index: gdbserver/linux-x86-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-x86-low.c,v retrieving revision 1.30 diff -p -r1.30 linux-x86-low.c *** gdbserver/linux-x86-low.c 15 Sep 2011 22:54:12 -0000 1.30 --- gdbserver/linux-x86-low.c 29 Oct 2011 00:37:57 -0000 *************** void init_registers_amd64_avx_linux (voi *** 42,47 **** --- 42,48 ---- void init_registers_i386_mmx_linux (void); static unsigned char jump_insn[] = { 0xe9, 0, 0, 0, 0 }; + static unsigned char small_jump_insn[] = { 0x66, 0xe9, 0, 0 }; /* Backward compatibility for gdb without XML support. */ *************** amd64_install_fast_tracepoint_jump_pad ( *** 1182,1191 **** CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end) { unsigned char buf[40]; int i, offset; --- 1183,1195 ---- CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end, ! char *err) { unsigned char buf[40]; int i, offset; *************** i386_install_fast_tracepoint_jump_pad (C *** 1346,1355 **** CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end) { unsigned char buf[0x100]; int i, offset; --- 1350,1362 ---- CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end, ! char *err) { unsigned char buf[0x100]; int i, offset; *************** i386_install_fast_tracepoint_jump_pad (C *** 1455,1461 **** buf[i++] = 0x0f; /* pop %fs */ buf[i++] = 0xa1; buf[i++] = 0x07; /* pop %es */ ! buf[i++] = 0x1f; /* pop %de */ buf[i++] = 0x9d; /* popf */ buf[i++] = 0x83; /* add $0x4,%esp (pop of tpaddr aka $pc) */ buf[i++] = 0xc4; --- 1462,1468 ---- buf[i++] = 0x0f; /* pop %fs */ buf[i++] = 0xa1; buf[i++] = 0x07; /* pop %es */ ! buf[i++] = 0x1f; /* pop %ds */ buf[i++] = 0x9d; /* popf */ buf[i++] = 0x83; /* add $0x4,%esp (pop of tpaddr aka $pc) */ buf[i++] = 0xc4; *************** i386_install_fast_tracepoint_jump_pad (C *** 1479,1489 **** is always done last (by our caller actually), so that we can install fast tracepoints with threads running. This relies on the agent's atomic write support. */ ! offset = *jump_entry - (tpaddr + sizeof (jump_insn)); ! memcpy (buf, jump_insn, sizeof (jump_insn)); ! memcpy (buf + 1, &offset, 4); ! memcpy (jjump_pad_insn, buf, sizeof (jump_insn)); ! *jjump_pad_insn_size = sizeof (jump_insn); /* Return the end address of our pad. */ *jump_entry = buildaddr; --- 1486,1525 ---- is always done last (by our caller actually), so that we can install fast tracepoints with threads running. This relies on the agent's atomic write support. */ ! if (orig_size == 4) ! { ! /* Create a trampoline. */ ! *trampoline_size = sizeof (jump_insn); ! if (!claim_trampoline_space (*trampoline_size, trampoline)) ! { ! /* No trampoline space available. */ ! strcpy (err, ! "E.Cannot allocate trampoline space needed for fast " ! "tracepoints on 4-byte instructions."); ! return 1; ! } ! ! offset = *jump_entry - (*trampoline + sizeof (jump_insn)); ! memcpy (buf, jump_insn, sizeof (jump_insn)); ! memcpy (buf + 1, &offset, 4); ! write_inferior_memory (*trampoline, buf, sizeof (jump_insn)); ! ! /* Use a 16-bit relative jump instruction to jump to the trampoline. */ ! offset = (*trampoline - (tpaddr + sizeof (small_jump_insn))) & 0xffff; ! memcpy (buf, small_jump_insn, sizeof (small_jump_insn)); ! memcpy (buf + 2, &offset, 2); ! memcpy (jjump_pad_insn, buf, sizeof (small_jump_insn)); ! *jjump_pad_insn_size = sizeof (small_jump_insn); ! } ! else ! { ! /* Else use a 32-bit relative jump instruction. */ ! offset = *jump_entry - (tpaddr + sizeof (jump_insn)); ! memcpy (buf, jump_insn, sizeof (jump_insn)); ! memcpy (buf + 1, &offset, 4); ! memcpy (jjump_pad_insn, buf, sizeof (jump_insn)); ! *jjump_pad_insn_size = sizeof (jump_insn); ! } /* Return the end address of our pad. */ *jump_entry = buildaddr; *************** x86_install_fast_tracepoint_jump_pad (CO *** 1497,1525 **** CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end) { #ifdef __x86_64__ if (register_size (0) == 8) return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr, collector, lockaddr, orig_size, jump_entry, jjump_pad_insn, jjump_pad_insn_size, adjusted_insn_addr, ! adjusted_insn_addr_end); #endif return i386_install_fast_tracepoint_jump_pad (tpoint, tpaddr, collector, lockaddr, orig_size, jump_entry, jjump_pad_insn, jjump_pad_insn_size, adjusted_insn_addr, ! adjusted_insn_addr_end); } static void --- 1533,1610 ---- CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end, ! char *err) { #ifdef __x86_64__ if (register_size (0) == 8) return amd64_install_fast_tracepoint_jump_pad (tpoint, tpaddr, collector, lockaddr, orig_size, jump_entry, + trampoline, trampoline_size, jjump_pad_insn, jjump_pad_insn_size, adjusted_insn_addr, ! adjusted_insn_addr_end, ! err); #endif return i386_install_fast_tracepoint_jump_pad (tpoint, tpaddr, collector, lockaddr, orig_size, jump_entry, + trampoline, trampoline_size, jjump_pad_insn, jjump_pad_insn_size, adjusted_insn_addr, ! adjusted_insn_addr_end, ! err); ! } ! ! /* Return the minimum instruction length for fast tracepoints on x86/x86-64 ! architectures. */ ! ! static int ! x86_get_min_fast_tracepoint_insn_len (void) ! { ! static int warned_about_fast_tracepoints = 0; ! ! #ifdef __x86_64__ ! /* On x86-64, 5-byte jump instructions with a 4-byte offset are always ! used for fast tracepoints. */ ! if (register_size (0) == 8) ! return 5; ! #endif ! ! if (in_process_agent_loaded ()) ! { ! char mybuf[100]; ! ! /* On x86, if trampolines are available, then 4-byte jump instructions ! with a 2-byte offset may be used, otherwise 5-byte jump instructions ! with a 4-byte offset are used instead. */ ! if (have_fast_tracepoint_trampoline_buffer (mybuf)) ! return 4; ! else ! { ! if (!warned_about_fast_tracepoints) ! { ! warning ("4-byte fast tracepoints not available; %s\n", mybuf); ! warned_about_fast_tracepoints = 1; ! } ! return 5; ! } ! } ! else ! { ! /* Indicate that the minimum length is currently unknown since the IPA ! has not loaded yet. */ ! return 0; ! } } static void *************** struct linux_target_ops the_low_target = *** 2873,2877 **** x86_supports_tracepoints, x86_get_thread_area, x86_install_fast_tracepoint_jump_pad, ! x86_emit_ops }; --- 2958,2963 ---- x86_supports_tracepoints, x86_get_thread_area, x86_install_fast_tracepoint_jump_pad, ! x86_emit_ops, ! x86_get_min_fast_tracepoint_insn_len, }; Index: gdbserver/server.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/server.h,v retrieving revision 1.87 diff -p -r1.87 server.h *** gdbserver/server.h 7 Oct 2011 12:06:48 -0000 1.87 --- gdbserver/server.h 29 Oct 2011 00:37:57 -0000 *************** void supply_fast_tracepoint_registers (s *** 494,501 **** --- 494,506 ---- void supply_static_tracepoint_registers (struct regcache *regcache, const unsigned char *regs, CORE_ADDR pc); + void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, + char *errmsg); #else void stop_tracing (void); + + int claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline); + int have_fast_tracepoint_trampoline_buffer (char *msgbuf); #endif /* Bytecode compilation function vector. */ Index: gdbserver/target.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/target.h,v retrieving revision 1.57 diff -p -r1.57 target.h *** gdbserver/target.h 7 Oct 2011 12:06:48 -0000 1.57 --- gdbserver/target.h 29 Oct 2011 00:37:57 -0000 *************** struct target_ops *** 359,378 **** pad lock object. ORIG_SIZE is the size in bytes of the instruction at TPADDR. JUMP_ENTRY points to the address of the jump pad entry, and on return holds the address past the end of ! the created jump pad. JJUMP_PAD_INSN is a buffer containing a ! copy of the instruction at TPADDR. ADJUST_INSN_ADDR and ! ADJUST_INSN_ADDR_END are output parameters that return the ! address range where the instruction at TPADDR was relocated ! to. */ int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr, CORE_ADDR collector, CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end); /* Return the bytecode operations vector for the current inferior. Returns NULL if bytecode compilation is not supported. */ --- 359,384 ---- pad lock object. ORIG_SIZE is the size in bytes of the instruction at TPADDR. JUMP_ENTRY points to the address of the jump pad entry, and on return holds the address past the end of ! the created jump pad. If a trampoline is created by the function, ! then TRAMPOLINE and TRAMPOLINE_SIZE return the address and size of ! the trampoline, else they remain unchanged. JJUMP_PAD_INSN is a ! buffer containing a copy of the instruction at TPADDR. ! ADJUST_INSN_ADDR and ADJUST_INSN_ADDR_END are output parameters that ! return the address range where the instruction at TPADDR was relocated ! to. If an error occurs, the ERR may be used to pass on an error ! message. */ int (*install_fast_tracepoint_jump_pad) (CORE_ADDR tpoint, CORE_ADDR tpaddr, CORE_ADDR collector, CORE_ADDR lockaddr, ULONGEST orig_size, CORE_ADDR *jump_entry, + CORE_ADDR *trampoline, + ULONGEST *trampoline_size, unsigned char *jjump_pad_insn, ULONGEST *jjump_pad_insn_size, CORE_ADDR *adjusted_insn_addr, ! CORE_ADDR *adjusted_insn_addr_end, ! char *err); /* Return the bytecode operations vector for the current inferior. Returns NULL if bytecode compilation is not supported. */ *************** struct target_ops *** 380,385 **** --- 386,395 ---- /* Returns true if the target supports disabling randomization. */ int (*supports_disable_randomization) (void); + + /* Return the minimum length of an instruction that can be safely overwritten + for use as a fast tracepoint. */ + int (*get_min_fast_tracepoint_insn_len) (void); }; extern struct target_ops *the_target; *************** void set_target_ops (struct target_ops * *** 437,442 **** --- 447,456 ---- #define target_supports_fast_tracepoints() \ (the_target->install_fast_tracepoint_jump_pad != NULL) + #define target_get_min_fast_tracepoint_insn_len() \ + (the_target->get_min_fast_tracepoint_insn_len \ + ? (*the_target->get_min_fast_tracepoint_insn_len) () : 0) + #define thread_stopped(thread) \ (*the_target->thread_stopped) (thread) *************** void set_target_ops (struct target_ops * *** 471,487 **** #define install_fast_tracepoint_jump_pad(tpoint, tpaddr, \ collector, lockaddr, \ orig_size, \ ! jump_entry, jjump_pad_insn, \ jjump_pad_insn_size, \ adjusted_insn_addr, \ ! adjusted_insn_addr_end) \ (*the_target->install_fast_tracepoint_jump_pad) (tpoint, tpaddr, \ collector,lockaddr, \ orig_size, jump_entry, \ jjump_pad_insn, \ jjump_pad_insn_size, \ adjusted_insn_addr, \ ! adjusted_insn_addr_end) #define target_emit_ops() \ (the_target->emit_ops ? (*the_target->emit_ops) () : NULL) --- 485,507 ---- #define install_fast_tracepoint_jump_pad(tpoint, tpaddr, \ collector, lockaddr, \ orig_size, \ ! jump_entry, \ ! trampoline, trampoline_size, \ ! jjump_pad_insn, \ jjump_pad_insn_size, \ adjusted_insn_addr, \ ! adjusted_insn_addr_end, \ ! err) \ (*the_target->install_fast_tracepoint_jump_pad) (tpoint, tpaddr, \ collector,lockaddr, \ orig_size, jump_entry, \ + trampoline, \ + trampoline_size, \ jjump_pad_insn, \ jjump_pad_insn_size, \ adjusted_insn_addr, \ ! adjusted_insn_addr_end, \ ! err) #define target_emit_ops() \ (the_target->emit_ops ? (*the_target->emit_ops) () : NULL) Index: gdbserver/tracepoint.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/tracepoint.c,v retrieving revision 1.27 diff -p -r1.27 tracepoint.c *** gdbserver/tracepoint.c 15 Sep 2011 22:54:13 -0000 1.27 --- gdbserver/tracepoint.c 29 Oct 2011 00:37:57 -0000 *************** trace_vdebug (const char *fmt, ...) *** 110,115 **** --- 110,118 ---- # define gdb_tp_heap_buffer gdb_agent_gdb_tp_heap_buffer # define gdb_jump_pad_buffer gdb_agent_gdb_jump_pad_buffer # define gdb_jump_pad_buffer_end gdb_agent_gdb_jump_pad_buffer_end + # define gdb_trampoline_buffer gdb_agent_gdb_trampoline_buffer + # define gdb_trampoline_buffer_end gdb_agent_gdb_trampoline_buffer_end + # define gdb_trampoline_buffer_error gdb_agent_gdb_trampoline_buffer_error # define collecting gdb_agent_collecting # define gdb_collect gdb_agent_gdb_collect # define stop_tracing gdb_agent_stop_tracing *************** struct ipa_sym_addresses *** 148,153 **** --- 151,159 ---- CORE_ADDR addr_gdb_tp_heap_buffer; CORE_ADDR addr_gdb_jump_pad_buffer; CORE_ADDR addr_gdb_jump_pad_buffer_end; + CORE_ADDR addr_gdb_trampoline_buffer; + CORE_ADDR addr_gdb_trampoline_buffer_end; + CORE_ADDR addr_gdb_trampoline_buffer_error; CORE_ADDR addr_collecting; CORE_ADDR addr_gdb_collect; CORE_ADDR addr_stop_tracing; *************** static struct *** 192,197 **** --- 198,206 ---- IPA_SYM(gdb_tp_heap_buffer), IPA_SYM(gdb_jump_pad_buffer), IPA_SYM(gdb_jump_pad_buffer_end), + IPA_SYM(gdb_trampoline_buffer), + IPA_SYM(gdb_trampoline_buffer_end), + IPA_SYM(gdb_trampoline_buffer_error), IPA_SYM(collecting), IPA_SYM(gdb_collect), IPA_SYM(stop_tracing), *************** struct tracepoint *** 658,663 **** --- 667,678 ---- CORE_ADDR jump_pad; CORE_ADDR jump_pad_end; + /* The address range of the piece of the trampoline buffer that was + assigned to this fast tracepoint. (_end is actually one byte + past the end). */ + CORE_ADDR trampoline; + CORE_ADDR trampoline_end; + /* The list of actions to take while in a stepping loop. These fields are only valid for patch-based tracepoints. */ int num_step_actions; *************** claim_jump_space (ULONGEST used) *** 2654,2659 **** --- 2669,2746 ---- gdb_jump_pad_head += used; } + static CORE_ADDR trampoline_buffer_head = 0; + static CORE_ADDR trampoline_buffer_tail; + + /* Reserve USED bytes from the trampoline buffer and return the + address of the start of the reserved space in TRAMPOLINE. Returns + non-zero if the space is successfully claimed. */ + + int + claim_trampoline_space (ULONGEST used, CORE_ADDR *trampoline) + { + if (!trampoline_buffer_head) + { + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer, + &trampoline_buffer_tail)) + { + fatal ("error extracting trampoline_buffer"); + return 0; + } + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, + &trampoline_buffer_head)) + { + fatal ("error extracting trampoline_buffer_end"); + return 0; + } + } + + /* Start claiming space from the top of the trampoline space. If + the space is located at the bottom of the virtual address space, + this reduces the possibility that corruption will occur if a null + pointer is used to write to memory. */ + if (trampoline_buffer_head - trampoline_buffer_tail < used) + { + trace_debug ("claim_trampoline_space failed to reserve %s bytes", + pulongest (used)); + return 0; + } + + trampoline_buffer_head -= used; + + trace_debug ("claim_trampoline_space reserves %s bytes at %s", + pulongest (used), paddress (trampoline_buffer_head)); + + *trampoline = trampoline_buffer_head; + return 1; + } + + /* Returns non-zero if there is space allocated for use in trampolines + for fast tracepoints. */ + + int + have_fast_tracepoint_trampoline_buffer (char *buf) + { + CORE_ADDR trampoline_end, errbuf; + + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, + &trampoline_end)) + fatal ("error extracting trampoline_buffer_end"); + + if (buf) + { + buf[0] = '\0'; + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_error, + &errbuf)) + fatal ("error extracting errbuf"); + + read_inferior_memory (errbuf, (unsigned char *) buf, 100); + } + + return trampoline_end != 0; + } + /* Sort tracepoints by PC, using a bubble sort. */ static void *************** cmd_qtstart (char *packet) *** 2818,2835 **** fjump_size); tpoint->jump_pad = prev_ftpoint->jump_pad; tpoint->jump_pad_end = prev_ftpoint->jump_pad_end; tpoint->adjusted_insn_addr = prev_ftpoint->adjusted_insn_addr; tpoint->adjusted_insn_addr_end = prev_ftpoint->adjusted_insn_addr_end; } else { ! CORE_ADDR jentry; int err = 0; prev_ftpoint = NULL; jentry = jump_entry = get_jump_space_head (); /* Install the jump pad. */ err = install_fast_tracepoint_jump_pad --- 2905,2934 ---- fjump_size); tpoint->jump_pad = prev_ftpoint->jump_pad; tpoint->jump_pad_end = prev_ftpoint->jump_pad_end; + tpoint->trampoline = prev_ftpoint->trampoline; + tpoint->trampoline_end = prev_ftpoint->trampoline_end; tpoint->adjusted_insn_addr = prev_ftpoint->adjusted_insn_addr; tpoint->adjusted_insn_addr_end = prev_ftpoint->adjusted_insn_addr_end; } else { ! CORE_ADDR jentry, trampoline; ! ULONGEST trampoline_size; int err = 0; + if (tpoint->orig_size < target_get_min_fast_tracepoint_insn_len ()) + { + trace_debug ("Requested a fast tracepoint on an instruction " + "that is of less than the minimum length."); + break; + } + prev_ftpoint = NULL; jentry = jump_entry = get_jump_space_head (); + trampoline = 0; + trampoline_size = 0; /* Install the jump pad. */ err = install_fast_tracepoint_jump_pad *************** cmd_qtstart (char *packet) *** 2839,2847 **** ipa_sym_addrs.addr_collecting, tpoint->orig_size, &jentry, fjump, &fjump_size, &tpoint->adjusted_insn_addr, ! &tpoint->adjusted_insn_addr_end); /* Wire it in. */ if (!err) --- 2938,2948 ---- ipa_sym_addrs.addr_collecting, tpoint->orig_size, &jentry, + &trampoline, &trampoline_size, fjump, &fjump_size, &tpoint->adjusted_insn_addr, ! &tpoint->adjusted_insn_addr_end, ! packet); /* Wire it in. */ if (!err) *************** cmd_qtstart (char *packet) *** 2852,2857 **** --- 2953,2960 ---- { tpoint->jump_pad = jump_entry; tpoint->jump_pad_end = jentry; + tpoint->trampoline = trampoline; + tpoint->trampoline_end = trampoline + trampoline_size; /* Pad to 8-byte alignment. */ jentry = ((jentry + 7) & ~0x7); *************** cmd_qtstmat (char *packet) *** 3435,3440 **** --- 3538,3552 ---- run_inferior_command (packet); } + /* Return the minimum instruction size needed for fast tracepoints as a + hexadecimal number. */ + + static void + cmd_qtminftpilen (char *packet) + { + sprintf (packet, "%x", target_get_min_fast_tracepoint_insn_len ()); + } + /* Respond to qTBuffer packet with a block of raw data from the trace buffer. GDB may ask for a lot, but we are allowed to reply with only as much as will fit within packet limits or whatever. */ *************** handle_tracepoint_query (char *packet) *** 3631,3636 **** --- 3743,3753 ---- cmd_qtstmat (packet); return 1; } + else if (strcmp ("qTMinFTPILen", packet) == 0) + { + cmd_qtminftpilen (packet); + return 1; + } return 0; } *************** fast_tracepoint_from_jump_pad_address (C *** 5180,5185 **** --- 5297,5319 ---- return NULL; } + /* Return the first fast tracepoint whose trampoline contains PC. */ + + static struct tracepoint * + fast_tracepoint_from_trampoline_address (CORE_ADDR pc) + { + struct tracepoint *tpoint; + + for (tpoint = tracepoints; tpoint; tpoint = tpoint->next) + { + if (tpoint->type == fast_tracepoint + && tpoint->trampoline <= pc && pc < tpoint->trampoline_end) + return tpoint; + } + + return NULL; + } + /* Return GDBserver's tracepoint that matches the IP Agent's tracepoint object that lives at IPA_TPOINT_OBJ in the IP Agent's address space. */ *************** fast_tracepoint_collecting (CORE_ADDR th *** 5242,5247 **** --- 5376,5383 ---- { CORE_ADDR ipa_collecting; CORE_ADDR ipa_gdb_jump_pad_buffer, ipa_gdb_jump_pad_buffer_end; + CORE_ADDR ipa_gdb_trampoline_buffer; + CORE_ADDR ipa_gdb_trampoline_buffer_end; struct tracepoint *tpoint; int needs_breakpoint; *************** fast_tracepoint_collecting (CORE_ADDR th *** 5280,5285 **** --- 5416,5428 ---- &ipa_gdb_jump_pad_buffer_end)) fatal ("error extracting `gdb_jump_pad_buffer_end'"); + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer, + &ipa_gdb_trampoline_buffer)) + fatal ("error extracting `gdb_trampoline_buffer'"); + if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_trampoline_buffer_end, + &ipa_gdb_trampoline_buffer_end)) + fatal ("error extracting `gdb_trampoline_buffer_end'"); + if (ipa_gdb_jump_pad_buffer <= stop_pc && stop_pc < ipa_gdb_jump_pad_buffer_end) { *************** fast_tracepoint_collecting (CORE_ADDR th *** 5308,5313 **** --- 5451,5480 ---- && stop_pc < tpoint->adjusted_insn_addr) needs_breakpoint = 1; } + else if (ipa_gdb_trampoline_buffer <= stop_pc + && stop_pc < ipa_gdb_trampoline_buffer_end) + { + /* We can tell which tracepoint(s) the thread is collecting by + matching the trampoline address back to the tracepoint. */ + tpoint = fast_tracepoint_from_trampoline_address (stop_pc); + if (tpoint == NULL) + { + warning ("in trampoline, but no matching tpoint?"); + return 0; + } + else + { + trace_debug ("in trampoline of tpoint (%d, %s); trampoline(%s, %s)", + tpoint->number, paddress (tpoint->address), + paddress (tpoint->trampoline), + paddress (tpoint->trampoline_end)); + } + + /* Have not reached jump pad yet, but treat the trampoline as a + part of the jump pad that is before the adjusted original + instruction. */ + needs_breakpoint = 1; + } else { collecting_t ipa_collecting_obj; *************** gdb_ust_init (void) *** 7621,7626 **** --- 7788,7809 ---- IP_AGENT_EXPORT char *gdb_tp_heap_buffer; IP_AGENT_EXPORT char *gdb_jump_pad_buffer; IP_AGENT_EXPORT char *gdb_jump_pad_buffer_end; + IP_AGENT_EXPORT char *gdb_trampoline_buffer; + IP_AGENT_EXPORT char *gdb_trampoline_buffer_end; + IP_AGENT_EXPORT char *gdb_trampoline_buffer_error; + + /* Record the result of getting buffer space for fast tracepoint + trampolines. Any error message is copied, since caller may not be + using persistent storage. */ + + void + set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end, char *errmsg) + { + gdb_trampoline_buffer = (char *) (uintptr_t) begin; + gdb_trampoline_buffer_end = (char *) (uintptr_t) end; + if (errmsg) + strncpy (gdb_trampoline_buffer_error, errmsg, 99); + } static void __attribute__ ((constructor)) initialize_tracepoint_ftlib (void) *************** initialize_tracepoint: mprotect(%p, %d, *** 7682,7687 **** --- 7865,7878 ---- gdb_jump_pad_buffer, pagesize * 20, strerror (errno)); } + gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0; + + /* It's not a fatal error for something to go wrong with trampoline + buffer setup, but it can be mysterious, so create a channel to + report back on what went wrong, using a fixed size since we may + not be able to allocate space later. */ + gdb_trampoline_buffer_error = xmalloc (100); + initialize_low_tracepoint (); #endif } Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.884 diff -p -r1.884 gdb.texinfo *** doc/gdb.texinfo 28 Oct 2011 14:48:59 -0000 1.884 --- doc/gdb.texinfo 29 Oct 2011 00:37:58 -0000 *************** encoded). @value{GDBN} will continue to *** 34774,34779 **** --- 34774,34781 ---- @itemx qTfP @itemx qTfV @itemx QTFrame + @itemx qTMinFTPILen + @xref{Tracepoint Packets}. @item qThreadExtraInfo,@var{thread-id} *************** numbers. *** 35297,35302 **** --- 35299,35323 ---- Like @samp{QTFrame:range:@var{start}:@var{end}}, but select the first frame @emph{outside} the given range of addresses (exclusive). + @item qTMinFTPILen + This packet requests the minimum length of instruction at which a fast + tracepoint may be placed. + + Replies: + + @table @samp + @item 0 + The minimum instruction length is currently unknown. + @item @var{length} + The minimum instruction length is @var{length}, where @var{length} is greater + or equal to 1. @var{length} is a hexadecimal number. A reply of 1 means + that a fast tracepoint may be placed on any instruction regardless of size. + @item E + An error has occurred. + @item + An empty reply indicates that the request is not supported by the stub. + @end table + @item QTStart Begin the tracepoint experiment. Begin collecting data from tracepoint hits in the trace frame buffer. This packet supports the