This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] [PR gdb/13463] linux-nat: Stop lwp before xfer if running


On 08/08/2013 08:59 PM, simon.marchi@polymtl.ca wrote:
> (err, resending with setting From: correctly, sorry about that)
> 
> Hi,
> 
> This is an attempt at finding a solution for PR 13463:
> http://sourceware.org/bugzilla/show_bug.cgi?id=13463
> 
> IMO, this is a serious bug (at least on x86 Linux). Inserting breakpoints
> while the inferior is running does not work. It can be triggered very easily:
> 
>     1. Start a simple program in non-stop/async mode.
>     2. Put a breakpoint anywhere in the program.
>     
> You should get an error like
> 
>     Cannot access memory at address 0x400504  
>   
> What happens is that GDB tries to ptrace read/write the inferior's memory
> while the process is not stopped, which is not supported.
> 
> The obvious/naive solution is to stop the process and resume it whenever
> we want to do a memory transfer while it is executing. 

Yeah, gdbserver does this.  Starts with prepare_to_access_memory.  A
prepare -> do -> "unprepare" sequence is possibly more efficient,
as we can batch several "do"s over a single pause sequence.  I've considered
before pushing that prepare/unprepare sequence all the way to gdb core,
in order to batch e.g., the whole of prologue analysis + breakpoint
insertion, or of shared library list reading, etc., but I thought all
the way through all that.

> I gave it a shot,
> and it seems to work for me, but there is probably some cases it does not
> cover, maybe other things it breaks or some better way to do it. I ran a
> make check and gdb.sum was identical before and after (minus the time).

Points I believe should be handled:

- it should not resume threads that were meant to be stopped,
  or were already stopped.  target_resume blindly does that.

- it's quite possible the thread you just tried to stop
  disappears/exit just as you tried to stop it, and then the
  xfer fails.

On the latter issue, and considering that there's no real
guarantee some other thread could be simultaneously poking
the same address gdbserver is (there's no ptrace atomic write),
gdbserver takes the easy route and always pauses all threads.
(the opposite end of the scale would be if gdb/gdbserver
force-cloned a thread in the inferior to use it as proxy to
peek/poke through.)


> 
> What do you think about it?
> 
> 	* linux-nat.c (linux_nat_xfer_partial): Interrupt during the
> 	memory transfer, if it is running.
> 
> ---
>  gdb/linux-nat.c |   18 ++++++++++++++++--
>  1 files changed, 16 insertions(+), 2 deletions(-)
> 
> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> index 45a6e5f..b8c0d1c 100644
> --- a/gdb/linux-nat.c
> +++ b/gdb/linux-nat.c
> @@ -294,8 +294,9 @@ static void linux_nat_async (void (*callback)
>  			      void *context),
>  			     void *context);
>  static int kill_lwp (int lwpid, int signo);
> -
> +static int linux_nat_stop_lwp (struct lwp_info *lwp, void *data);
>  static int stop_callback (struct lwp_info *lp, void *data);
> +static void cleanup_target_stop(void *arg);
>  
>  static void block_child_signals (sigset_t *prev_mask);
>  static void restore_child_signals_mask (sigset_t *prev_mask);
> @@ -4205,11 +4206,24 @@ linux_nat_xfer_partial (struct target_ops *ops, enum target_object object,
>    old_chain = save_inferior_ptid ();
>  
>    if (is_lwp (inferior_ptid))
> -    inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));
> +    {
> +      struct lwp_info* lwp;
> +      inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid));
> +
> +      lwp = find_lwp_pid (inferior_ptid);
> +      if (target_async_permitted && lwp != NULL && !lwp->stopped)
> +	{
> +	  make_cleanup (cleanup_target_stop, &lwp->ptid);
> +	  linux_nat_stop_lwp (lwp, NULL);
> +	  stop_wait_callback (lwp, NULL);
> +	}
> +    }
> +
>  
>    xfer = linux_ops->to_xfer_partial (ops, object, annex, readbuf, writebuf,
>  				     offset, len);
>    do_cleanups (old_chain);
>    return xfer;
>  }
> 

-- 
Pedro Alves


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]