Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Michael Snyder <msnyder@vmware.com>
To: Pedro Alves <pedro@codesourcery.com>
Cc: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Subject: Re: [commit] [gdbserver/linux] access memory of running processes
Date: Thu, 26 Aug 2010 23:29:00 -0000	[thread overview]
Message-ID: <4C76F8B8.9050502@vmware.com> (raw)
In-Reply-To: <201008270026.22929.pedro@codesourcery.com>

Hmmm, don't like "unprepare_to_access_memory".

What about "finish_accessing_memory"?


Pedro Alves wrote:
> Of all the debug API's we've added non-stop support to (we've added
> it to a few private targets), linux/ptrace is the only one so far that
> does not allow accessing memory when you pass it the PID of a process
> that is presently running to work with.  This affects the user experience
> much, as any command that touches memory, even breakpoint command fail with a
> hard error if you happen to have a running thread selected.  The workaround is
> to stop one thread, switch to it, do what you need, and re-resume the thread.
> You may leave all other threads running while doing that workaround.
> Obviously, this is cumbersome.  Particularly more so since random commands
> that weren't accessing target memory yesterday, may do so today.
> 
> I've been thinking of whether this should be addressed on the target
> side, or if it should be addressed by GDB.  Fixing this on the GDB side
> implies GDB interrupting a process, doing the access, and resuming it again.
> Since not all targets need this, it would have to be dependent on a target
> flag.  Fixing this on the target side means doing the temporarily-pause work,
> but it ends up resolving faster, because there's no inherent RSP latency
> involved.  The latter option is completely transparent to GDB, of course.
> 
> Thinking about it, I came up with the following points and conclusions:
> 
>  - Making sure that GDB has a consistent view of memory across a batch of
> memory accesses is something that is desired in some scenarios but not
> actually necessary in others, meaning, it's an independent issue from allowing
> a single access while threads are running.  The former always needs to be
> addressed by having GDB take the wheel.  The latter can be addressed in either
> way.
> 
>  - This is really a debug API issue.  The fact that we have to access an
> address space by passing to ptrace a stopped lwp is just a consequence of the
> fact that you always have to pass a stopped process to all ptrace API calls.
> 
>  - The current RSP memory access and breakpoint commands have synchronous
> semantics.  Doesn't sound like a strong argument, but, let me explain that I
> considered having gdbserver immediately reply OK to Z0 breakpoints if the
> target is running (and so GDB was happy), have gdbserver force an asynchronous
> stop on the current inferior, and finally insert the breakpoint when the
> inferior stops, and then transparently resume it.  The problem is, if the
> breakpoint fails to insert, because say, its address wasn't actually mapped in
> the address space, there's no way to inform GDB.  It's obviously worse with
> memory read/write packets.  Sure, we could come up with new RSP packets, but,
> as long as we have what we have, we might as well make them work (particularly
> since they work for most targets without extra fuss anyway) (synchronously) on
> linux too, and come up with new packets if we really find this way to be
> limiting.
> 
> There are few ways to be smart here, but I've chosen to be as dumb as
> possible, and then more dumb --- transparently stop all lwps at selected entry
> points of memory accesses corresponding to requests coming in from GDB.  Since
> the need for this is target specific, I've abstracted this out in new
> prepare_to_access_memory/unprepare_to_access_memory target methods.
> 
> Tested on x86_64-unknown-linux-gnu and applied.
> 
> --
> Pedro Alves
> 
> 2010-08-26  Pedro Alves  <pedro@codesourcery.com>
> 
>         gdbserver/
>         * linux-low.c (linux_prepare_to_access_memory): New.
>         (linux_unprepare_to_access_memory): New.
>         (linux_target_ops): Install them.
>         * server.c (read_memory): Rename to ...
>         (gdb_read_memory): ... this.  Use
>         prepare_to_access_memory/prepare_to_access_memory.
>         (write_memory): Rename to ...
>         (gdb_write_memory): ... this.  Use
>         prepare_to_access_memory/prepare_to_access_memory.
>         (handle_search_memory_1): Adjust.
>         (process_serial_event): Adjust.
>         * target.h (struct target_ops): New fields
>         prepare_to_access_memory and unprepare_to_access_memory.
>         (prepare_to_access_memory, unprepare_to_access_memory): New.
>         * linux-x86-low.c (x86_insert_point, x86_remove_point): Use
>         prepare_to_access_memory/prepare_to_access_memory.
>         * nto-low.c (nto_target_ops): Adjust.
>         * spu-low.c (spu_target_ops): Adjust.
>         * win32-low.c (win32_target_ops): Adjust.
> 
> ---
>  gdb/gdbserver/linux-low.c     |   21 +++++++++++++++++++++
>  gdb/gdbserver/linux-x86-low.c |   24 +++++++++++++++++++++---
>  gdb/gdbserver/nto-low.c       |    2 ++
>  gdb/gdbserver/server.c        |   39 +++++++++++++++++++++++++++++----------
>  gdb/gdbserver/spu-low.c       |    2 ++
>  gdb/gdbserver/target.h        |   29 +++++++++++++++++++++++++++++
>  gdb/gdbserver/win32-low.c     |    2 ++
>  7 files changed, 106 insertions(+), 13 deletions(-)
> 
> Index: src/gdb/gdbserver/linux-low.c
> ===================================================================
> --- src.orig/gdb/gdbserver/linux-low.c  2010-08-26 19:32:03.000000000 +0100
> +++ src/gdb/gdbserver/linux-low.c       2010-08-26 21:14:56.000000000 +0100
> @@ -5006,6 +5006,25 @@ linux_unpause_all (int unfreeze)
>  }
> 
>  static int
> +linux_prepare_to_access_memory (void)
> +{
> +  /* Neither ptrace nor /proc/PID/mem allow accessing memory through a
> +     running LWP.  */
> +  if (non_stop)
> +    linux_pause_all (1);
> +  return 0;
> +}
> +
> +static void
> +linux_unprepare_to_access_memory (void)
> +{
> +  /* Neither ptrace nor /proc/PID/mem allow accessing memory through a
> +     running LWP.  */
> +  if (non_stop)
> +    linux_unpause_all (1);
> +}
> +
> +static int
>  linux_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
>                                         CORE_ADDR collector,
>                                         CORE_ADDR lockaddr,
> @@ -5043,6 +5062,8 @@ static struct target_ops linux_target_op
>    linux_wait,
>    linux_fetch_registers,
>    linux_store_registers,
> +  linux_prepare_to_access_memory,
> +  linux_unprepare_to_access_memory,
>    linux_read_memory,
>    linux_write_memory,
>    linux_look_up_symbols,
> Index: src/gdb/gdbserver/server.c
> ===================================================================
> --- src.orig/gdb/gdbserver/server.c     2010-08-26 16:37:50.000000000 +0100
> +++ src/gdb/gdbserver/server.c  2010-08-26 19:38:25.000000000 +0100
> @@ -539,8 +539,10 @@ monitor_show_help (void)
>  /* Read trace frame or inferior memory.  */
> 
>  static int
> -read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
> +gdb_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
>  {
> +  int ret;
> +
>    if (current_traceframe >= 0)
>      {
>        ULONGEST nbytes;
> @@ -558,19 +560,36 @@ read_memory (CORE_ADDR memaddr, unsigned
>        /* (assume no half-trace half-real blocks for now) */
>      }
> 
> -  return read_inferior_memory (memaddr, myaddr, len);
> +  ret = prepare_to_access_memory ();
> +  if (ret == 0)
> +    {
> +      ret = read_inferior_memory (memaddr, myaddr, len);
> +      unprepare_to_access_memory ();
> +    }
> +
> +  return ret;
>  }
> 
>  /* Write trace frame or inferior memory.  Actually, writing to trace
>     frames is forbidden.  */
> 
>  static int
> -write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
> +gdb_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
>  {
>    if (current_traceframe >= 0)
>      return EIO;
>    else
> -    return write_inferior_memory (memaddr, myaddr, len);
> +    {
> +      int ret;
> +
> +      ret = prepare_to_access_memory ();
> +      if (ret == 0)
> +       {
> +         ret = write_inferior_memory (memaddr, myaddr, len);
> +         unprepare_to_access_memory ();
> +       }
> +      return ret;
> +    }
>  }
> 
>  /* Subroutine of handle_search_memory to simplify it.  */
> @@ -584,7 +603,7 @@ handle_search_memory_1 (CORE_ADDR start_
>  {
>    /* Prime the search buffer.  */
> 
> -  if (read_memory (start_addr, search_buf, search_buf_size) != 0)
> +  if (gdb_read_memory (start_addr, search_buf, search_buf_size) != 0)
>      {
>        warning ("Unable to access target memory at 0x%lx, halting search.",
>                (long) start_addr);
> @@ -635,8 +654,8 @@ handle_search_memory_1 (CORE_ADDR start_
>                         ? search_space_len - keep_len
>                         : chunk_size);
> 
> -         if (read_memory (read_addr, search_buf + keep_len,
> -                                   nr_to_read) != 0)
> +         if (gdb_read_memory (read_addr, search_buf + keep_len,
> +                              nr_to_read) != 0)
>             {
>               warning ("Unable to access target memory at 0x%lx, halting search.",
>                        (long) read_addr);
> @@ -2924,7 +2943,7 @@ process_serial_event (void)
>      case 'm':
>        require_running (own_buf);
>        decode_m_packet (&own_buf[1], &mem_addr, &len);
> -      if (read_memory (mem_addr, mem_buf, len) == 0)
> +      if (gdb_read_memory (mem_addr, mem_buf, len) == 0)
>         convert_int_to_ascii (mem_buf, own_buf, len);
>        else
>         write_enn (own_buf);
> @@ -2932,7 +2951,7 @@ process_serial_event (void)
>      case 'M':
>        require_running (own_buf);
>        decode_M_packet (&own_buf[1], &mem_addr, &len, &mem_buf);
> -      if (write_memory (mem_addr, mem_buf, len) == 0)
> +      if (gdb_write_memory (mem_addr, mem_buf, len) == 0)
>         write_ok (own_buf);
>        else
>         write_enn (own_buf);
> @@ -2941,7 +2960,7 @@ process_serial_event (void)
>        require_running (own_buf);
>        if (decode_X_packet (&own_buf[1], packet_len - 1,
>                            &mem_addr, &len, &mem_buf) < 0
> -         || write_memory (mem_addr, mem_buf, len) != 0)
> +         || gdb_write_memory (mem_addr, mem_buf, len) != 0)
>         write_enn (own_buf);
>        else
>         write_ok (own_buf);
> Index: src/gdb/gdbserver/target.h
> ===================================================================
> --- src.orig/gdb/gdbserver/target.h     2010-08-26 16:37:50.000000000 +0100
> +++ src/gdb/gdbserver/target.h  2010-08-26 21:28:50.000000000 +0100
> @@ -181,6 +181,23 @@ struct target_ops
> 
>    void (*store_registers) (struct regcache *regcache, int regno);
> 
> +  /* Prepare to read or write memory from the inferior process.
> +     Targets use this to do what is necessary to get the state of the
> +     inferior such that it is possible to access memory.
> +
> +     This should generally only be called from client facing routines,
> +     such as gdb_read_memory/gdb_write_memory, or the insert_point
> +     callbacks.
> +
> +     Like `read_memory' and `write_memory' below, returns 0 on success
> +     and errno on failure.  */
> +
> +  int (*prepare_to_access_memory) (void);
> +
> +  /* Undo the effects of prepare_to_access_memory.  */
> +
> +  void (*unprepare_to_access_memory) (void);
> +
>    /* Read memory from the inferior process.  This should generally be
>       called through read_inferior_memory, which handles breakpoint shadowing.
> 
> @@ -469,6 +486,18 @@ int start_non_stop (int nonstop);
>  ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
>                int connected_wait);
> 
> +#define prepare_to_access_memory()             \
> +  (the_target->prepare_to_access_memory                \
> +   ? (*the_target->prepare_to_access_memory) () \
> +   : 0)
> +
> +#define unprepare_to_access_memory()                   \
> +  do                                                   \
> +    {                                                  \
> +      if (the_target->unprepare_to_access_memory)      \
> +       (*the_target->unprepare_to_access_memory) ();   \
> +    } while (0)
> +
>  int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len);
> 
>  int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
> Index: src/gdb/gdbserver/linux-x86-low.c
> ===================================================================
> --- src.orig/gdb/gdbserver/linux-x86-low.c      2010-08-26 21:03:47.000000000 +0100
> +++ src/gdb/gdbserver/linux-x86-low.c   2010-08-26 21:04:19.000000000 +0100
> @@ -546,7 +546,7 @@ i386_dr_low_get_status (void)
>    return x86_linux_dr_get (ptid, DR_STATUS);
>  }
> 
> -/* Watchpoint support.  */
> +/* Breakpoint/Watchpoint support.  */
> 
>  static int
>  x86_insert_point (char type, CORE_ADDR addr, int len)
> @@ -555,7 +555,16 @@ x86_insert_point (char type, CORE_ADDR a
>    switch (type)
>      {
>      case '0':
> -      return set_gdb_breakpoint_at (addr);
> +      {
> +       int ret;
> +
> +       ret = prepare_to_access_memory ();
> +       if (ret)
> +         return -1;
> +       ret = set_gdb_breakpoint_at (addr);
> +       unprepare_to_access_memory ();
> +       return ret;
> +      }
>      case '2':
>      case '3':
>      case '4':
> @@ -574,7 +583,16 @@ x86_remove_point (char type, CORE_ADDR a
>    switch (type)
>      {
>      case '0':
> -      return delete_gdb_breakpoint_at (addr);
> +      {
> +       int ret;
> +
> +       ret = prepare_to_access_memory ();
> +       if (ret)
> +         return -1;
> +       ret = delete_gdb_breakpoint_at (addr);
> +       unprepare_to_access_memory ();
> +       return ret;
> +      }
>      case '2':
>      case '3':
>      case '4':
> Index: src/gdb/gdbserver/nto-low.c
> ===================================================================
> --- src.orig/gdb/gdbserver/nto-low.c    2010-06-16 10:55:22.000000000 +0100
> +++ src/gdb/gdbserver/nto-low.c 2010-08-26 21:07:28.000000000 +0100
> @@ -913,6 +913,8 @@ static struct target_ops nto_target_ops
>    nto_wait,
>    nto_fetch_registers,
>    nto_store_registers,
> +  NULL, /* prepare_to_access_memory */
> +  NULL, /* unprepare_to_access_memory */
>    nto_read_memory,
>    nto_write_memory,
>    NULL, /* nto_look_up_symbols */
> Index: src/gdb/gdbserver/spu-low.c
> ===================================================================
> --- src.orig/gdb/gdbserver/spu-low.c    2010-06-20 23:17:44.000000000 +0100
> +++ src/gdb/gdbserver/spu-low.c 2010-08-26 21:07:54.000000000 +0100
> @@ -653,6 +653,8 @@ static struct target_ops spu_target_ops
>    spu_wait,
>    spu_fetch_registers,
>    spu_store_registers,
> +  NULL, /* prepare_to_access_memory */
> +  NULL, /* unprepare_to_access_memory */
>    spu_read_memory,
>    spu_write_memory,
>    spu_look_up_symbols,
> Index: src/gdb/gdbserver/win32-low.c
> ===================================================================
> --- src.orig/gdb/gdbserver/win32-low.c  2010-06-16 10:58:30.000000000 +0100
> +++ src/gdb/gdbserver/win32-low.c       2010-08-26 21:08:16.000000000 +0100
> @@ -1781,6 +1781,8 @@ static struct target_ops win32_target_op
>    win32_wait,
>    win32_fetch_inferior_registers,
>    win32_store_inferior_registers,
> +  NULL, /* prepare_to_access_memory */
> +  NULL, /* unprepare_to_access_memory */
>    win32_read_inferior_memory,
>    win32_write_inferior_memory,
>    NULL, /* lookup_symbols */


  reply	other threads:[~2010-08-26 23:29 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-26 23:26 Pedro Alves
2010-08-26 23:29 ` Michael Snyder [this message]
2010-08-27  0:02   ` Pedro Alves
2010-08-27  0:04     ` Michael Snyder
2010-08-27  0:19       ` Pedro Alves

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4C76F8B8.9050502@vmware.com \
    --to=msnyder@vmware.com \
    --cc=gdb-patches@sourceware.org \
    --cc=pedro@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox