From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11540 invoked by alias); 11 Apr 2013 02:43:56 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 11501 invoked by uid 89); 11 Apr 2013 02:43:56 -0000 X-Spam-SWARE-Status: No, score=-4.6 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,TW_CP autolearn=ham version=3.3.1 Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Thu, 11 Apr 2013 02:43:55 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1UQ7UP-00035g-CT from Yao_Qi@mentor.com for gdb-patches@sourceware.org; Wed, 10 Apr 2013 19:43:53 -0700 Received: from SVR-ORW-FEM-04.mgc.mentorg.com ([147.34.97.41]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Wed, 10 Apr 2013 19:43:53 -0700 Received: from qiyao.dyndns.org.dyndns.org (147.34.91.1) by svr-orw-fem-04.mgc.mentorg.com (147.34.97.41) with Microsoft SMTP Server id 14.1.289.1; Wed, 10 Apr 2013 19:43:52 -0700 From: Yao Qi To: Subject: [PATCH 3/7] range stepping: gdbserver on x86/linux Date: Thu, 11 Apr 2013 06:18:00 -0000 Message-ID: <1365648222-12540-4-git-send-email-yao@codesourcery.com> In-Reply-To: <1365648222-12540-1-git-send-email-yao@codesourcery.com> References: <1363006291-13334-1-git-send-email-yao@codesourcery.com> <1365648222-12540-1-git-send-email-yao@codesourcery.com> MIME-Version: 1.0 Content-Type: text/plain X-SW-Source: 2013-04/txt/msg00300.txt.bz2 This patch adds the support of range stepping in GDBserver for x86/linux. gdb/gdbserver: 2013-03-11 Yao Qi * gdbthread.h (struct thread_info) : New fields. (thread_in_range_stepping_p): Declare. (thread_clear_range_stepping): Declare. * inferiors.c (thread_clear_range_stepping): New. (add_thread): Call thread_clear_range_stepping. (thread_in_range_stepping_p): New. * linux-low.c (linux_wait_1): Call thread_in_range_stepping_p to check if report stop to GDB. Call thread_clear_range_stepping. (linux_supports_range_stepping): New. (linux_target_ops): Initialize 'supports_range_stepping' to linux_supports_range_stepping. * linux-low.h (struct linux_target_ops) : New field. * linux-x86-low.c (x86_supports_range_stepping): New. (the_low_target): Initialize 'supports_range_stepping' to * server.c (handle_v_cont): Handle action 'r'. (handle_v_requests): Append ";r" if target supports range stepping. * target.h (struct target_ops) >: New field. (target_supports_range_stepping): New macro. --- gdb/gdbserver/gdbthread.h | 6 ++++++ gdb/gdbserver/inferiors.c | 19 +++++++++++++++++++ gdb/gdbserver/linux-low.c | 38 +++++++++++++++++++++++++++++++++++--- gdb/gdbserver/linux-low.h | 2 ++ gdb/gdbserver/linux-x86-low.c | 7 +++++++ gdb/gdbserver/server.c | 40 ++++++++++++++++++++++++++++++++++++++++ gdb/gdbserver/target.h | 6 ++++++ 7 files changed, 115 insertions(+), 3 deletions(-) diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h index 5d4955b..fbd768b 100644 --- a/gdb/gdbserver/gdbthread.h +++ b/gdb/gdbserver/gdbthread.h @@ -62,12 +62,18 @@ struct thread_info /* Branch trace target information for this thread. */ struct btrace_target_info *btrace; + + /* The start and end address of range stepping. */ + CORE_ADDR start, end; }; extern struct inferior_list all_threads; void remove_thread (struct thread_info *thread); void add_thread (ptid_t ptid, void *target_data); +int thread_in_range_stepping_p (struct thread_info *thread, + CORE_ADDR pc); +void thread_clear_range_stepping (struct thread_info *thread); struct thread_info *find_thread_ptid (ptid_t ptid); struct thread_info *gdb_id_to_thread (unsigned int); diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 6953d0e..2184a7b 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -85,6 +85,15 @@ remove_inferior (struct inferior_list *list, list->tail = *cur; } +/* Clear the state of range stepping of THREAD. */ + +void +thread_clear_range_stepping (struct thread_info *thread) +{ + thread->start = 0; + thread->end = 0; +} + void add_thread (ptid_t thread_id, void *target_data) { @@ -103,6 +112,16 @@ add_thread (ptid_t thread_id, void *target_data) new_thread->target_data = target_data; set_inferior_regcache_data (new_thread, new_register_cache ()); + thread_clear_range_stepping (new_thread); +} + +/* Return true if THREAD is in range stepping. PC is the value of pc + of THREAD. */ + +int +thread_in_range_stepping_p (struct thread_info *thread, CORE_ADDR pc) +{ + return (pc >= thread->start && pc < thread->end); } ptid_t diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 72c51e0..e9879cc 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -2313,6 +2313,7 @@ linux_wait_1 (ptid_t ptid, int maybe_internal_trap; int report_to_gdb; int trace_event; + int in_range_stepping; /* Translate generic target options into linux options. */ options = __WALL; @@ -2322,6 +2323,7 @@ linux_wait_1 (ptid_t ptid, retry: bp_explains_trap = 0; trace_event = 0; + in_range_stepping = 0; ourstatus->kind = TARGET_WAITKIND_IGNORE; /* If we were only supposed to resume one thread, only wait for @@ -2615,6 +2617,9 @@ Check if we're already there.\n", goto retry; } + in_range_stepping + = thread_in_range_stepping_p (current_inferior, + event_child->stop_pc); /* If GDB wanted this thread to single step, we always want to report the SIGTRAP, and let GDB handle it. Watchpoints should always be reported. So should signals we can't explain. A @@ -2624,9 +2629,12 @@ Check if we're already there.\n", internal breakpoint and still reporting the event to GDB. If we don't, we're out of luck, GDB won't see the breakpoint hit. */ report_to_gdb = (!maybe_internal_trap - || current_inferior->last_resume_kind == resume_step + /* Report the event back to GDB if the inferior is + stepping and not in range stepping. */ + || (current_inferior->last_resume_kind == resume_step + && !in_range_stepping) || event_child->stopped_by_watchpoint - || (!step_over_finished + || (!step_over_finished && !in_range_stepping && !bp_explains_trap && !trace_event) || (gdb_breakpoint_here (event_child->stop_pc) && gdb_condition_true_at_breakpoint (event_child->stop_pc) @@ -2647,6 +2655,12 @@ Check if we're already there.\n", fprintf (stderr, "Step-over finished.\n"); if (trace_event) fprintf (stderr, "Tracepoint event.\n"); + if (thread_in_range_stepping_p (current_inferior, + event_child->stop_pc)) + fprintf (stderr, "Range stepping pc 0x%s [0x%s, 0x%s).\n", + paddress (event_child->stop_pc), + paddress (current_inferior->start), + paddress (current_inferior->end)); } /* We're not reporting this breakpoint to GDB, so apply the @@ -2678,7 +2692,13 @@ Check if we're already there.\n", if (debug_threads) { if (current_inferior->last_resume_kind == resume_step) - fprintf (stderr, "GDB wanted to single-step, reporting event.\n"); + { + if (!thread_in_range_stepping_p (current_inferior, + event_child->stop_pc)) + fprintf (stderr, "Range stepping is done, reporting event.\n"); + else + fprintf (stderr, "GDB wanted to single-step, reporting event.\n"); + } if (event_child->stopped_by_watchpoint) fprintf (stderr, "Stopped by watchpoint.\n"); if (gdb_breakpoint_here (event_child->stop_pc)) @@ -2687,6 +2707,8 @@ Check if we're already there.\n", fprintf (stderr, "Hit a non-gdbserver trap event.\n"); } + thread_clear_range_stepping (current_inferior); + /* Alright, we're going to report a stop. */ if (!non_stop && !stabilizing_threads) @@ -5083,6 +5105,15 @@ linux_supports_agent (void) return 1; } +static int +linux_supports_range_stepping (void) +{ + if (*the_low_target.supports_range_stepping == NULL) + return 0; + + return (*the_low_target.supports_range_stepping) (); +} + /* Enumerate spufs IDs for process PID. */ static int spu_enumerate_spu_ids (long pid, unsigned char *buf, CORE_ADDR offset, int len) @@ -5939,6 +5970,7 @@ static struct target_ops linux_target_ops = { NULL, NULL, #endif + linux_supports_range_stepping, }; static void diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index 27dd3b5..5d3e8cf 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -168,6 +168,8 @@ struct linux_target_ops for use as a fast tracepoint. */ int (*get_min_fast_tracepoint_insn_len) (void); + /* Returns true if the low target supports range stepping. */ + int (*supports_range_stepping) (void); }; extern struct linux_target_ops the_low_target; diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index 31657d3..1d1df95 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -3175,6 +3175,12 @@ x86_emit_ops (void) return &i386_emit_ops; } +static int +x86_supports_range_stepping (void) +{ + return 1; +} + /* This is initialized assuming an amd64 target. x86_arch_setup will correct it for i386 or amd64 targets. */ @@ -3214,4 +3220,5 @@ struct linux_target_ops the_low_target = x86_install_fast_tracepoint_jump_pad, x86_emit_ops, x86_get_min_fast_tracepoint_insn_len, + x86_supports_range_stepping, }; diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 6bb36d8..aa4ddf6 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -2040,10 +2040,15 @@ handle_v_cont (char *own_buf) p = &own_buf[5]; while (*p) { + CORE_ADDR start = 0; + CORE_ADDR end = 0; + p++; if (p[0] == 's' || p[0] == 'S') resume_info[i].kind = resume_step; + else if (p[0] == 'r') + resume_info[i].kind = resume_step; else if (p[0] == 'c' || p[0] == 'C') resume_info[i].kind = resume_continue; else if (p[0] == 't') @@ -2063,6 +2068,21 @@ handle_v_cont (char *own_buf) goto err; resume_info[i].sig = gdb_signal_to_host (sig); } + else if (p[0] == 'r') + { + char *p1; + + p = p + 1; + p1 = strchr (p, ','); + decode_address (&start, p, p1 - p); + + p = p1 + 1; + p1 = strchr (p, ':'); + decode_address (&end, p, p1 - p); + + resume_info[i].sig = 0; + p = p1; + } else { resume_info[i].sig = 0; @@ -2088,6 +2108,21 @@ handle_v_cont (char *own_buf) goto err; resume_info[i].thread = ptid; + if (end > 0) + { + struct thread_info *tp = find_thread_ptid (ptid); + + /* GDB should not send range stepping for all threads of + a process, like 'vCont;rSTART,END:pPID.-1', TP can't + be NULL. */ + gdb_assert (tp != NULL); + + tp->start = start; + tp->end = end; + + start = 0; + end = 0; + } i++; } @@ -2311,6 +2346,11 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len) if (strncmp (own_buf, "vCont?", 6) == 0) { strcpy (own_buf, "vCont;c;C;s;S;t"); + if (target_supports_range_stepping ()) + { + own_buf = own_buf + strlen (own_buf); + strcpy (own_buf, ";r"); + } return; } } diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index f257459..8c0790e 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -414,6 +414,8 @@ struct target_ops to break a cyclic dependency. */ void (*read_btrace) (struct btrace_target_info *, struct buffer *, int type); + /* Return true if target supports range stepping. */ + int (*supports_range_stepping) (void); }; extern struct target_ops *the_target; @@ -549,6 +551,10 @@ int kill_inferior (int); #define target_read_btrace(tinfo, buffer, type) \ (*the_target->read_btrace) (tinfo, buffer, type) +#define target_supports_range_stepping() \ + (the_target->supports_range_stepping ? \ + (*the_target->supports_range_stepping) () : 0) + /* Start non-stop mode, returns 0 on success, -1 on failure. */ int start_non_stop (int nonstop); -- 1.7.7.6