gdb: make displaced stepping implementation capable of managing multiple buffers
authorSimon Marchi <simon.marchi@efficios.com>
Fri, 4 Dec 2020 21:43:56 +0000 (16:43 -0500)
committerSimon Marchi <simon.marchi@efficios.com>
Fri, 4 Dec 2020 21:43:56 +0000 (16:43 -0500)
The displaced_step_buffer class, introduced in the previous patch,
manages access to a single displaced step buffer.  Change it into
displaced_step_buffers (note the plural), which manages access to
multiple displaced step buffers.

When preparing a displaced step for a thread, it looks for an unused
buffer.

For now, all users still pass a single displaced step buffer, so no real
behavior change is expected here.  The following patch makes a user pass
more than one buffer, so the functionality introduced by this patch is
going to be useful in the next one.

gdb/ChangeLog:

* displaced-stepping.h (struct displaced_step_buffer): Rename
to...
(struct displaced_step_buffers): ... this.
<m_addr, m_current_thread, m_copy_insn_closure>: Remove.
<struct displaced_step_buffer>: New inner class.
<m_buffers>: New.
* displaced-stepping.c (displaced_step_buffer::prepare): Rename
to...
(displaced_step_buffers::prepare): ... this, adjust for multiple
buffers.
(displaced_step_buffer::finish):  Rename to...
(displaced_step_buffers::finish): ... this, adjust for multiple
buffers.
(displaced_step_buffer::copy_insn_closure_by_addr): Rename to...
(displaced_step_buffers::copy_insn_closure_by_addr): ... this,
adjust for multiple buffers.
(displaced_step_buffer::restore_in_ptid): Rename to...
(displaced_step_buffers::restore_in_ptid): ... this, adjust for
multiple buffers.
* linux-tdep.h (linux_init_abi): Change supports_displaced_step
for num_disp_step_buffers.
* linux-tdep.c (struct linux_gdbarch_data)
<num_disp_step_buffers>: New field.
(struct linux_info) <disp_step_buf>: Rename to...
<disp_step_bufs>: ... this, change type to
displaced_step_buffers.
(linux_displaced_step_prepare): Use
linux_gdbarch_data::num_disp_step_buffers to create that number
of buffers.
(linux_displaced_step_finish): Adjust.
(linux_displaced_step_copy_insn_closure_by_addr): Adjust.
(linux_displaced_step_restore_all_in_ptid): Adjust.
(linux_init_abi): Change supports_displaced_step parameter for
num_disp_step_buffers, save it in linux_gdbarch_data.
* aarch64-linux-tdep.c (aarch64_linux_init_abi): Adjust.
* alpha-linux-tdep.c (alpha_linux_init_abi): Adjust.
* amd64-linux-tdep.c (amd64_linux_init_abi_common): Change
supports_displaced_step parameter for num_disp_step_buffers.
(amd64_linux_init_abi): Adjust.
(amd64_x32_linux_init_abi): Adjust.
* arc-linux-tdep.c (arc_linux_init_osabi): Adjust.
* arm-linux-tdep.c (arm_linux_init_abi): Adjust.
* bfin-linux-tdep.c (bfin_linux_init_abi): Adjust.
* cris-linux-tdep.c (cris_linux_init_abi): Adjust.
* csky-linux-tdep.c (csky_linux_init_abi): Adjust.
* frv-linux-tdep.c (frv_linux_init_abi): Adjust.
* hppa-linux-tdep.c (hppa_linux_init_abi): Adjust.
* i386-linux-tdep.c (i386_linux_init_abi): Adjust.
* ia64-linux-tdep.c (ia64_linux_init_abi): Adjust.
* m32r-linux-tdep.c (m32r_linux_init_abi): Adjust.
* m68k-linux-tdep.c (m68k_linux_init_abi):
* microblaze-linux-tdep.c (microblaze_linux_init_abi):
* mips-linux-tdep.c (mips_linux_init_abi): Adjust.
* mn10300-linux-tdep.c (am33_linux_init_osabi): Adjust.
* nios2-linux-tdep.c (nios2_linux_init_abi): Adjust.
* or1k-linux-tdep.c (or1k_linux_init_abi): Adjust.
* ppc-linux-tdep.c (ppc_linux_init_abi): Adjust.
* riscv-linux-tdep.c (riscv_linux_init_abi): Adjust.
* rs6000-tdep.c (struct ppc_inferior_data) <disp_step_buf>:
Change type to displaced_step_buffers.
* s390-linux-tdep.c (s390_linux_init_abi_any): Adjust.
* sh-linux-tdep.c (sh_linux_init_abi): Adjust.
* sparc-linux-tdep.c (sparc32_linux_init_abi): Adjust.
* sparc64-linux-tdep.c (sparc64_linux_init_abi): Adjust.
* tic6x-linux-tdep.c (tic6x_uclinux_init_abi): Adjust.
* tilegx-linux-tdep.c (tilegx_linux_init_abi): Adjust.
* xtensa-linux-tdep.c (xtensa_linux_init_abi): Adjust.

Change-Id: Ia9c02f207da2c9e1d9188020139619122392bb70

34 files changed:
gdb/ChangeLog
gdb/aarch64-linux-tdep.c
gdb/alpha-linux-tdep.c
gdb/amd64-linux-tdep.c
gdb/arc-linux-tdep.c
gdb/arm-linux-tdep.c
gdb/bfin-linux-tdep.c
gdb/cris-linux-tdep.c
gdb/csky-linux-tdep.c
gdb/displaced-stepping.c
gdb/displaced-stepping.h
gdb/frv-linux-tdep.c
gdb/hppa-linux-tdep.c
gdb/i386-linux-tdep.c
gdb/ia64-linux-tdep.c
gdb/linux-tdep.c
gdb/linux-tdep.h
gdb/m32r-linux-tdep.c
gdb/m68k-linux-tdep.c
gdb/microblaze-linux-tdep.c
gdb/mips-linux-tdep.c
gdb/mn10300-linux-tdep.c
gdb/nios2-linux-tdep.c
gdb/or1k-linux-tdep.c
gdb/ppc-linux-tdep.c
gdb/riscv-linux-tdep.c
gdb/rs6000-tdep.c
gdb/s390-linux-tdep.c
gdb/sh-linux-tdep.c
gdb/sparc-linux-tdep.c
gdb/sparc64-linux-tdep.c
gdb/tic6x-linux-tdep.c
gdb/tilegx-linux-tdep.c
gdb/xtensa-linux-tdep.c

index d79b2217dea7659f63eda2eba7d05b3f2246c064..514bf6d0c53fd8162a6f67448776cf80c166196d 100644 (file)
@@ -1,3 +1,73 @@
+2020-12-04  Simon Marchi  <simon.marchi@efficios.com>
+
+       * displaced-stepping.h (struct displaced_step_buffer): Rename
+       to...
+       (struct displaced_step_buffers): ... this.
+       <m_addr, m_current_thread, m_copy_insn_closure>: Remove.
+       <struct displaced_step_buffer>: New inner class.
+       <m_buffers>: New.
+       * displaced-stepping.c (displaced_step_buffer::prepare): Rename
+       to...
+       (displaced_step_buffers::prepare): ... this, adjust for multiple
+       buffers.
+       (displaced_step_buffer::finish):  Rename to...
+       (displaced_step_buffers::finish): ... this, adjust for multiple
+       buffers.
+       (displaced_step_buffer::copy_insn_closure_by_addr): Rename to...
+       (displaced_step_buffers::copy_insn_closure_by_addr): ... this,
+       adjust for multiple buffers.
+       (displaced_step_buffer::restore_in_ptid): Rename to...
+       (displaced_step_buffers::restore_in_ptid): ... this, adjust for
+       multiple buffers.
+       * linux-tdep.h (linux_init_abi): Change supports_displaced_step
+       for num_disp_step_buffers.
+       * linux-tdep.c (struct linux_gdbarch_data)
+       <num_disp_step_buffers>: New field.
+       (struct linux_info) <disp_step_buf>: Rename to...
+       <disp_step_bufs>: ... this, change type to
+       displaced_step_buffers.
+       (linux_displaced_step_prepare): Use
+       linux_gdbarch_data::num_disp_step_buffers to create that number
+       of buffers.
+       (linux_displaced_step_finish): Adjust.
+       (linux_displaced_step_copy_insn_closure_by_addr): Adjust.
+       (linux_displaced_step_restore_all_in_ptid): Adjust.
+       (linux_init_abi): Change supports_displaced_step parameter for
+       num_disp_step_buffers, save it in linux_gdbarch_data.
+       * aarch64-linux-tdep.c (aarch64_linux_init_abi): Adjust.
+       * alpha-linux-tdep.c (alpha_linux_init_abi): Adjust.
+       * amd64-linux-tdep.c (amd64_linux_init_abi_common): Change
+       supports_displaced_step parameter for num_disp_step_buffers.
+       (amd64_linux_init_abi): Adjust.
+       (amd64_x32_linux_init_abi): Adjust.
+       * arc-linux-tdep.c (arc_linux_init_osabi): Adjust.
+       * arm-linux-tdep.c (arm_linux_init_abi): Adjust.
+       * bfin-linux-tdep.c (bfin_linux_init_abi): Adjust.
+       * cris-linux-tdep.c (cris_linux_init_abi): Adjust.
+       * csky-linux-tdep.c (csky_linux_init_abi): Adjust.
+       * frv-linux-tdep.c (frv_linux_init_abi): Adjust.
+       * hppa-linux-tdep.c (hppa_linux_init_abi): Adjust.
+       * i386-linux-tdep.c (i386_linux_init_abi): Adjust.
+       * ia64-linux-tdep.c (ia64_linux_init_abi): Adjust.
+       * m32r-linux-tdep.c (m32r_linux_init_abi): Adjust.
+       * m68k-linux-tdep.c (m68k_linux_init_abi):
+       * microblaze-linux-tdep.c (microblaze_linux_init_abi):
+       * mips-linux-tdep.c (mips_linux_init_abi): Adjust.
+       * mn10300-linux-tdep.c (am33_linux_init_osabi): Adjust.
+       * nios2-linux-tdep.c (nios2_linux_init_abi): Adjust.
+       * or1k-linux-tdep.c (or1k_linux_init_abi): Adjust.
+       * ppc-linux-tdep.c (ppc_linux_init_abi): Adjust.
+       * riscv-linux-tdep.c (riscv_linux_init_abi): Adjust.
+       * rs6000-tdep.c (struct ppc_inferior_data) <disp_step_buf>:
+       Change type to displaced_step_buffers.
+       * s390-linux-tdep.c (s390_linux_init_abi_any): Adjust.
+       * sh-linux-tdep.c (sh_linux_init_abi): Adjust.
+       * sparc-linux-tdep.c (sparc32_linux_init_abi): Adjust.
+       * sparc64-linux-tdep.c (sparc64_linux_init_abi): Adjust.
+       * tic6x-linux-tdep.c (tic6x_uclinux_init_abi): Adjust.
+       * tilegx-linux-tdep.c (tilegx_linux_init_abi): Adjust.
+       * xtensa-linux-tdep.c (xtensa_linux_init_abi): Adjust.
+
 2020-12-04  Simon Marchi  <simon.marchi@efficios.com>
 
        * linux-tdep.c (init_linux_gdbarch_data): Change parameter to
index 4fe7babe59cf2ae5c9579447d3dc3ef4079ca647..ce697ff246e16ad55475a07d36091c1165139a3d 100644 (file)
@@ -1445,7 +1445,7 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   tdep->lowest_pc = 0x8000;
 
-  linux_init_abi (info, gdbarch, true);
+  linux_init_abi (info, gdbarch, 1);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
                                         svr4_lp64_fetch_link_map_offsets);
index a6d6b15e9fd62adef19e6a50adad0bafa22bca8b..520dd980d88d44b5fc377bd09d56eddcaa1b37e5 100644 (file)
@@ -356,7 +356,7 @@ alpha_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep;
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Hook into the DWARF CFI frame unwinder.  */
   alpha_dwarf2_init_abi (info, gdbarch);
index a81bb9039df5294bd26f429230844ef3d490cfb2..60707ed7aaffe52b08068ca6b5e0369af8239192 100644 (file)
@@ -1796,11 +1796,11 @@ amd64_dtrace_parse_probe_argument (struct gdbarch *gdbarch,
 
 static void
 amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch,
-                           bool supports_displaced_step)
+                           int num_disp_step_buffers)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, supports_displaced_step);
+  linux_init_abi (info, gdbarch, num_disp_step_buffers);
 
   tdep->sigtramp_p = amd64_linux_sigtramp_p;
   tdep->sigcontext_addr = amd64_linux_sigcontext_addr;
@@ -1880,7 +1880,7 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   if (!valid_p)
     return;
 
-  amd64_linux_init_abi_common (info, gdbarch, true);
+  amd64_linux_init_abi_common (info, gdbarch, 1);
 
   /* Initialize the amd64_linux_record_tdep.  */
   /* These values are the size of the type that will be used in a system
@@ -2095,7 +2095,7 @@ amd64_x32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   if (!valid_p)
     return;
 
-  amd64_linux_init_abi_common (info, gdbarch, false);
+  amd64_linux_init_abi_common (info, gdbarch, 0);
 
   /* Initialize the amd64_x32_linux_record_tdep.  */
   /* These values are the size of the type that will be used in a system
index b919882177e6aa78d730b7b2faf62a6e97080fa4..2bdeaaf0614cd34375996207926ae8b1fa65682e 100644 (file)
@@ -439,7 +439,7 @@ arc_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
    */
   tdep->jb_pc = 15;
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Set up target dependent GDB architecture entries.  */
   set_gdbarch_cannot_fetch_register (gdbarch, arc_linux_cannot_fetch_register);
index d164cff3dff7069001c46dd8f86914ef56c38e7f..11e71e56b46ceaa2e6eab236fbf77214e67fee34 100644 (file)
@@ -1721,7 +1721,7 @@ arm_linux_init_abi (struct gdbarch_info info,
                                                                    NULL };
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, true);
+  linux_init_abi (info, gdbarch, 1);
 
   tdep->lowest_pc = 0x8000;
   if (info.byte_order_for_code == BFD_ENDIAN_BIG)
index fc2f1d9ac656ea6824493edb569398db6895b151..bc2bb1aad4533c68ebd287a8e5a43fc4f61d508f 100644 (file)
@@ -150,7 +150,7 @@ bfin_linux_get_syscall_number (struct gdbarch *gdbarch,
 static void
 bfin_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Set the sigtramp frame sniffer.  */
   tramp_frame_prepend_unwinder (gdbarch, &bfin_linux_sigframe);
index 85cbf4cc0931c79b6f3fe00a887727366928a781..4ae1cdd1390aedf68d345a9dd57dccb922fa2cc0 100644 (file)
@@ -35,7 +35,7 @@ cris_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   if (tdep->cris_version == 32)
     /* Threaded debugging is only supported on CRISv32 for now.  */
index 184fa5ffb239b528b5839a46f2867910d39bc9cb..a0d32b5f2d0ca640869079e98a102135ed4114df 100644 (file)
@@ -233,7 +233,7 @@ csky_linux_rt_sigreturn_tramp_frame = {
 static void
 csky_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Shared library handling.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
index fb5d23f92c1449ce4621adea3921e3f2506b7aa7..10aa3da62ab46b499cf568277c30b4f7ceeb262f 100644 (file)
@@ -44,82 +44,121 @@ show_debug_displaced (struct ui_file *file, int from_tty,
 }
 
 displaced_step_prepare_status
-displaced_step_buffer::prepare (thread_info *thread, CORE_ADDR &displaced_pc)
+displaced_step_buffers::prepare (thread_info *thread, CORE_ADDR &displaced_pc)
 {
   gdb_assert (!thread->displaced_step_state.in_progress ());
 
-  /* Is a thread currently using the buffer?  */
-  if (m_current_thread != nullptr)
-    {
-      /* If so, it better not be this thread.  */
-      gdb_assert (thread != m_current_thread);
-      return DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
-    }
+  /* Sanity check: the thread should not be using a buffer at this point.  */
+  for (displaced_step_buffer &buf : m_buffers)
+    gdb_assert (buf.current_thread != thread);
 
   regcache *regcache = get_thread_regcache (thread);
   const address_space *aspace = regcache->aspace ();
   gdbarch *arch = regcache->arch ();
   ULONGEST len = gdbarch_max_insn_length (arch);
 
-  if (breakpoint_in_range_p (aspace, m_addr, len))
-    {
-      /* There's a breakpoint set in the scratch pad location range
-        (which is usually around the entry point).  We'd either
-        install it before resuming, which would overwrite/corrupt the
-        scratch pad, or if it was already inserted, this displaced
-        step would overwrite it.  The latter is OK in the sense that
-        we already assume that no thread is going to execute the code
-        in the scratch pad range (after initial startup) anyway, but
-        the former is unacceptable.  Simply punt and fallback to
-        stepping over this breakpoint in-line.  */
-      displaced_debug_printf ("breakpoint set in scratch pad.  "
-                             "Stepping over breakpoint in-line instead.");
+  /* Search for an unused buffer.  */
+  displaced_step_buffer *buffer = nullptr;
+  displaced_step_prepare_status fail_status
+    = DISPLACED_STEP_PREPARE_STATUS_CANT;
 
-      return DISPLACED_STEP_PREPARE_STATUS_CANT;
+  for (displaced_step_buffer &candidate : m_buffers)
+    {
+      bool bp_in_range = breakpoint_in_range_p (aspace, candidate.addr, len);
+      bool is_free = candidate.current_thread == nullptr;
+
+      if (!bp_in_range)
+       {
+         if (is_free)
+           {
+             buffer = &candidate;
+             break;
+           }
+         else
+           {
+             /* This buffer would be suitable, but it's used right now.  */
+             fail_status = DISPLACED_STEP_PREPARE_STATUS_UNAVAILABLE;
+           }
+       }
+      else
+       {
+         /* There's a breakpoint set in the scratch pad location range
+            (which is usually around the entry point).  We'd either
+            install it before resuming, which would overwrite/corrupt the
+            scratch pad, or if it was already inserted, this displaced
+            step would overwrite it.  The latter is OK in the sense that
+            we already assume that no thread is going to execute the code
+            in the scratch pad range (after initial startup) anyway, but
+            the former is unacceptable.  Simply punt and fallback to
+            stepping over this breakpoint in-line.  */
+         displaced_debug_printf ("breakpoint set in displaced stepping "
+                                 "buffer at %s, can't use.",
+                                 paddress (arch, candidate.addr));
+       }
     }
 
-  m_original_pc = regcache_read_pc (regcache);
-  displaced_pc = m_addr;
+  if (buffer == nullptr)
+    return fail_status;
+
+  displaced_debug_printf ("selected buffer at %s",
+                         paddress (arch, buffer->addr));
+
+  /* Save the original PC of the thread.  */
+  buffer->original_pc = regcache_read_pc (regcache);
+
+  /* Return displaced step buffer address to caller.  */
+  displaced_pc = buffer->addr;
 
   /* Save the original contents of the displaced stepping buffer.  */
-  m_saved_copy.resize (len);
+  buffer->saved_copy.resize (len);
 
-  int status = target_read_memory (m_addr, m_saved_copy.data (), len);
+  int status = target_read_memory (buffer->addr,
+                                   buffer->saved_copy.data (), len);
   if (status != 0)
     throw_error (MEMORY_ERROR,
                 _("Error accessing memory address %s (%s) for "
                   "displaced-stepping scratch space."),
-                paddress (arch, m_addr), safe_strerror (status));
+                paddress (arch, buffer->addr), safe_strerror (status));
 
   displaced_debug_printf ("saved %s: %s",
-                         paddress (arch, m_addr),
+                         paddress (arch, buffer->addr),
                          displaced_step_dump_bytes
-                           (m_saved_copy.data (), len).c_str ());
+                         (buffer->saved_copy.data (), len).c_str ());
 
   /* Save this in a local variable first, so it's released if code below
      throws.  */
   displaced_step_copy_insn_closure_up copy_insn_closure
-    = gdbarch_displaced_step_copy_insn (arch, m_original_pc, m_addr, regcache);
+    = gdbarch_displaced_step_copy_insn (arch, buffer->original_pc,
+                                       buffer->addr, regcache);
 
   if (copy_insn_closure == nullptr)
     {
       /* The architecture doesn't know how or want to displaced step
-        this instruction or instruction sequence.  Fallback to
-        stepping over the breakpoint in-line.  */
+        this instruction or instruction sequence.  Fallback to
+        stepping over the breakpoint in-line.  */
       return DISPLACED_STEP_PREPARE_STATUS_CANT;
     }
 
   /* Resume execution at the copy.  */
-  regcache_write_pc (regcache, m_addr);
+  regcache_write_pc (regcache, buffer->addr);
 
   /* This marks the buffer as being in use.  */
-  m_current_thread = thread;
+  buffer->current_thread = thread;
 
   /* Save this, now that we know everything went fine.  */
-  m_copy_insn_closure = std::move (copy_insn_closure);
+  buffer->copy_insn_closure = std::move (copy_insn_closure);
 
-  /* Tell infrun not to try preparing a displaced step again for this inferior.  */
+  /* Tell infrun not to try preparing a displaced step again for this inferior if
+     all buffers are taken.  */
   thread->inf->displaced_step_state.unavailable = true;
+  for (const displaced_step_buffer &buf : m_buffers)
+    {
+      if (buf.current_thread == nullptr)
+       {
+         thread->inf->displaced_step_state.unavailable = false;
+         break;
+       }
+    }
 
   return DISPLACED_STEP_PREPARE_STATUS_OK;
 }
@@ -152,21 +191,34 @@ displaced_step_instruction_executed_successfully (gdbarch *arch,
 }
 
 displaced_step_finish_status
-displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
-                              gdb_signal sig)
+displaced_step_buffers::finish (gdbarch *arch, thread_info *thread,
+                               gdb_signal sig)
 {
   gdb_assert (thread->displaced_step_state.in_progress ());
-  gdb_assert (thread == m_current_thread);
+
+  /* Find the buffer this thread was using.  */
+  displaced_step_buffer *buffer = nullptr;
+
+  for (displaced_step_buffer &candidate : m_buffers)
+    {
+      if (candidate.current_thread == thread)
+       {
+         buffer = &candidate;
+         break;
+       }
+    }
+
+  gdb_assert (buffer != nullptr);
 
   /* Move this to a local variable so it's released in case something goes
      wrong.  */
   displaced_step_copy_insn_closure_up copy_insn_closure
-    = std::move (m_copy_insn_closure);
+    = std::move (buffer->copy_insn_closure);
   gdb_assert (copy_insn_closure != nullptr);
 
-  /* Reset M_CURRENT_THREAD immediately to mark the buffer as available, in case
-     something goes wrong below.  */
-  m_current_thread = nullptr;
+  /* Reset BUFFER->CURRENT_THREAD immediately to mark the buffer as available,
+     in case something goes wrong below.  */
+  buffer->current_thread = nullptr;
 
   /* Now that a buffer gets freed, tell infrun it can ask us to prepare a displaced
      step again for this inferior.  Do that here in case something goes wrong
@@ -175,12 +227,13 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
 
   ULONGEST len = gdbarch_max_insn_length (arch);
 
-  write_memory_ptid (thread->ptid, m_addr,
-                    m_saved_copy.data (), len);
+  /* Restore memory of the buffer.  */
+  write_memory_ptid (thread->ptid, buffer->addr,
+                    buffer->saved_copy.data (), len);
 
   displaced_debug_printf ("restored %s %s",
                          target_pid_to_str (thread->ptid).c_str (),
-                         paddress (arch, m_addr));
+                         paddress (arch, buffer->addr));
 
   regcache *rc = get_thread_regcache (thread);
 
@@ -189,8 +242,9 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
 
   if (instruction_executed_successfully)
     {
-      gdbarch_displaced_step_fixup (arch, copy_insn_closure.get (), m_original_pc,
-                                   m_addr, rc);
+      gdbarch_displaced_step_fixup (arch, copy_insn_closure.get (),
+                                   buffer->original_pc,
+                                   buffer->addr, rc);
       return DISPLACED_STEP_FINISH_STATUS_OK;
     }
   else
@@ -198,35 +252,41 @@ displaced_step_buffer::finish (gdbarch *arch, thread_info *thread,
       /* Since the instruction didn't complete, all we can do is relocate the
         PC.  */
       CORE_ADDR pc = regcache_read_pc (rc);
-      pc = m_original_pc + (pc - m_addr);
+      pc = buffer->original_pc + (pc - buffer->addr);
       regcache_write_pc (rc, pc);
       return DISPLACED_STEP_FINISH_STATUS_NOT_EXECUTED;
     }
 }
 
 const displaced_step_copy_insn_closure *
-displaced_step_buffer::copy_insn_closure_by_addr (CORE_ADDR addr)
+displaced_step_buffers::copy_insn_closure_by_addr (CORE_ADDR addr)
 {
-  if (addr == m_addr)
-    return m_copy_insn_closure.get ();
-  else
-    return nullptr;
+  for (const displaced_step_buffer &buffer : m_buffers)
+    {
+      if (addr == buffer.addr)
+       return buffer.copy_insn_closure.get ();
+    }
+
+  return nullptr;
 }
 
 void
-displaced_step_buffer::restore_in_ptid (ptid_t ptid)
+displaced_step_buffers::restore_in_ptid (ptid_t ptid)
 {
-  if (m_current_thread != nullptr)
+  for (const displaced_step_buffer &buffer : m_buffers)
     {
-      regcache *regcache = get_thread_regcache (m_current_thread);
+      if (buffer.current_thread == nullptr)
+       continue;
+
+      regcache *regcache = get_thread_regcache (buffer.current_thread);
       gdbarch *arch = regcache->arch ();
       ULONGEST len = gdbarch_max_insn_length (arch);
 
-      write_memory_ptid (ptid, m_addr, m_saved_copy.data (), len);
+      write_memory_ptid (ptid, buffer.addr, buffer.saved_copy.data (), len);
 
       displaced_debug_printf ("restored in ptid %s %s",
                              target_pid_to_str (ptid).c_str (),
-                             paddress (arch, m_addr));
+                             paddress (arch, buffer.addr));
     }
 }
 
index a2d80aeda4f30c46da4353bc22bc1a3c1974089a..d1a1cebb93e17623d93bea8ce481a6a9942dff97 100644 (file)
@@ -20,6 +20,7 @@
 #ifndef DISPLACED_STEPPING_H
 #define DISPLACED_STEPPING_H
 
+#include "gdbsupport/array-view.h"
 #include "gdbsupport/byte-vector.h"
 
 struct gdbarch;
@@ -154,13 +155,19 @@ private:
   gdbarch *m_original_gdbarch = nullptr;
 };
 
-/* Manage access to a single displaced stepping buffer.  */
+/* Control access to multiple displaced stepping buffers at fixed addresses.  */
 
-struct displaced_step_buffer
+struct displaced_step_buffers
 {
-  explicit displaced_step_buffer (CORE_ADDR buffer_addr)
-    : m_addr (buffer_addr)
-  {}
+  explicit displaced_step_buffers (gdb::array_view<CORE_ADDR> buffer_addrs)
+  {
+    gdb_assert (buffer_addrs.size () > 0);
+
+    m_buffers.reserve (buffer_addrs.size ());
+
+    for (CORE_ADDR buffer_addr : buffer_addrs)
+      m_buffers.emplace_back (buffer_addr);
+  }
 
   displaced_step_prepare_status prepare (thread_info *thread,
                                         CORE_ADDR &displaced_pc);
@@ -174,21 +181,35 @@ struct displaced_step_buffer
   void restore_in_ptid (ptid_t ptid);
 
 private:
-  /* Original PC of the instruction being displaced-stepped in this buffer.  */
-  CORE_ADDR m_original_pc = 0;
 
-  /* Address of the buffer.  */
-  const CORE_ADDR m_addr;
+  /* State of a single buffer.  */
+
+  struct displaced_step_buffer
+  {
+    explicit displaced_step_buffer (CORE_ADDR addr)
+      : addr (addr)
+    {}
+
+    /* Address of the buffer.  */
+    const CORE_ADDR addr;
+
+    /* The original PC of the instruction currently being stepped.  */
+    CORE_ADDR original_pc = 0;
+
+    /* If set, the thread currently using the buffer.  If unset, the buffer is not
+       used.  */
+    thread_info *current_thread = nullptr;
 
-  /* If set, the thread currently using the buffer.  */
-  thread_info *m_current_thread = nullptr;
+    /* Saved copy of the bytes in the displaced buffer, to be restored once the
+       buffer is no longer used.  */
+    gdb::byte_vector saved_copy;
 
-  /* Saved contents of copy area.  */
-  gdb::byte_vector m_saved_copy;
+    /* Closure obtained from gdbarch_displaced_step_copy_insn, to be passed to
+       gdbarch_displaced_step_fixup_insn.  */
+    displaced_step_copy_insn_closure_up copy_insn_closure;
+  };
 
-  /* The closure provided gdbarch_displaced_step_copy_insn, to be used
-     for post-step cleanup.  */
-  displaced_step_copy_insn_closure_up m_copy_insn_closure;
+  std::vector<displaced_step_buffer> m_buffers;
 };
 
 #endif /* DISPLACED_STEPPING_H */
index c5ae4212ab449f0331f0d4872a26c209f66e6595..c5b20737654fda1caba21e1a2e14b2f0876d6b31 100644 (file)
@@ -456,7 +456,7 @@ frv_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
 static void
 frv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Set the sigtramp frame sniffer.  */
   frame_unwind_append_unwinder (gdbarch, &frv_linux_sigtramp_frame_unwind); 
index a171e582e595ca90108d1b0468dba4a8cc3de5c7..ce85f327d1e41ed2c359ae4b68b76e08baeae05f 100644 (file)
@@ -489,7 +489,7 @@ hppa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* GNU/Linux is always ELF.  */
   tdep->is_elf = 1;
index 1b209fd3efff7e3d1141bef4ad7085ae849b916c..90ee30969aa1e3ef652b09cf4952d1b6c2e29411 100644 (file)
@@ -832,7 +832,7 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   gdb_assert (tdesc_data);
 
-  linux_init_abi (info, gdbarch, true);
+  linux_init_abi (info, gdbarch, 1);
 
   /* GNU/Linux uses ELF.  */
   i386_elf_init_abi (info, gdbarch);
index d6d581ab3dda294d8022208170c2e6b507c6a627..3a69f758c11fb7006d7659fccbdea9a2469b654c 100644 (file)
@@ -223,7 +223,7 @@ ia64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   static const char *const stap_register_indirection_suffixes[] = { "]",
                                                                    NULL };
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Set the method of obtaining the sigcontext addresses at which
      registers are saved.  */
index 57ea45cf6b6b5df9abe8ec980b17275d0890777d..5ae28d826c1a75d65c2e0ab40f414182a133d22b 100644 (file)
@@ -166,9 +166,10 @@ enum
 static struct gdbarch_data *linux_gdbarch_data_handle;
 
 struct linux_gdbarch_data
-  {
-    struct type *siginfo_type;
-  };
+{
+  struct type *siginfo_type;
+  int num_disp_step_buffers;
+};
 
 static void *
 init_linux_gdbarch_data (struct obstack *obstack)
@@ -200,8 +201,8 @@ struct linux_info
      if we tried looking it up but failed.  */
   int vsyscall_range_p = 0;
 
-  /* Inferior's displaced step buffer.  */
-  gdb::optional<displaced_step_buffer> disp_step_buf;
+  /* Inferior's displaced step buffers.  */
+  gdb::optional<displaced_step_buffers> disp_step_bufs;
 };
 
 /* Per-inferior data key.  */
@@ -2540,15 +2541,25 @@ linux_displaced_step_prepare (gdbarch *arch, thread_info *thread,
 {
   linux_info *per_inferior = get_linux_inferior_data (thread->inf);
 
-  if (!per_inferior->disp_step_buf.has_value ())
+  if (!per_inferior->disp_step_bufs.has_value ())
     {
+      /* Figure out the location of the buffers.  They are contiguous, starting
+        at DISP_STEP_BUF_ADDR.  They are all of size BUF_LEN.  */
       CORE_ADDR disp_step_buf_addr
        = linux_displaced_step_location (thread->inf->gdbarch);
+      int buf_len = gdbarch_max_insn_length (arch);
 
-      per_inferior->disp_step_buf.emplace (disp_step_buf_addr);
+      linux_gdbarch_data *gdbarch_data = get_linux_gdbarch_data (arch);
+      gdb_assert (gdbarch_data->num_disp_step_buffers > 0);
+
+      std::vector<CORE_ADDR> buffers;
+      for (int i = 0; i < gdbarch_data->num_disp_step_buffers; i++)
+       buffers.push_back (disp_step_buf_addr + i * buf_len);
+
+      per_inferior->disp_step_bufs.emplace (buffers);
     }
 
-  return per_inferior->disp_step_buf->prepare (thread, displaced_pc);
+  return per_inferior->disp_step_bufs->prepare (thread, displaced_pc);
 }
 
 /* See linux-tdep.h.  */
@@ -2558,9 +2569,9 @@ linux_displaced_step_finish (gdbarch *arch, thread_info *thread, gdb_signal sig)
 {
   linux_info *per_inferior = get_linux_inferior_data (thread->inf);
 
-  gdb_assert (per_inferior->disp_step_buf.has_value ());
+  gdb_assert (per_inferior->disp_step_bufs.has_value ());
 
-  return per_inferior->disp_step_buf->finish (arch, thread, sig);
+  return per_inferior->disp_step_bufs->finish (arch, thread, sig);
 }
 
 /* See linux-tdep.h.  */
@@ -2571,10 +2582,10 @@ linux_displaced_step_copy_insn_closure_by_addr (inferior *inf, CORE_ADDR addr)
   linux_info *per_inferior = linux_inferior_data.get (inf);
 
   if (per_inferior == nullptr
-      || !per_inferior->disp_step_buf.has_value ())
+      || !per_inferior->disp_step_bufs.has_value ())
     return nullptr;
 
-  return per_inferior->disp_step_buf->copy_insn_closure_by_addr (addr);
+  return per_inferior->disp_step_bufs->copy_insn_closure_by_addr (addr);
 }
 
 /* See linux-tdep.h.  */
@@ -2585,10 +2596,10 @@ linux_displaced_step_restore_all_in_ptid (inferior *parent_inf, ptid_t ptid)
   linux_info *per_inferior = linux_inferior_data.get (parent_inf);
 
   if (per_inferior == nullptr
-      || !per_inferior->disp_step_buf.has_value ())
+      || !per_inferior->disp_step_bufs.has_value ())
     return;
 
-  per_inferior->disp_step_buf->restore_in_ptid (ptid);
+  per_inferior->disp_step_bufs->restore_in_ptid (ptid);
 }
 
 /* See linux-tdep.h.  */
@@ -2636,15 +2647,22 @@ show_dump_excluded_mappings (struct ui_file *file, int from_tty,
 }
 
 /* To be called from the various GDB_OSABI_LINUX handlers for the
-   various GNU/Linux architectures and machine types.  */
+   various GNU/Linux architectures and machine types.
+
+   NUM_DISP_STEP_BUFFERS is the number of displaced step buffers to use.  If 0,
+   displaced stepping is not supported. */
 
 void
 linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
-               bool supports_displaced_step)
+               int num_disp_step_buffers)
 {
-  if (supports_displaced_step)
+  if (num_disp_step_buffers > 0)
     {
-      set_gdbarch_displaced_step_prepare (gdbarch, linux_displaced_step_prepare);
+      linux_gdbarch_data *gdbarch_data = get_linux_gdbarch_data (gdbarch);
+      gdbarch_data->num_disp_step_buffers = num_disp_step_buffers;
+
+      set_gdbarch_displaced_step_prepare (gdbarch,
+                                         linux_displaced_step_prepare);
       set_gdbarch_displaced_step_finish (gdbarch, linux_displaced_step_finish);
       set_gdbarch_displaced_step_copy_insn_closure_by_addr
        (gdbarch, linux_displaced_step_copy_insn_closure_by_addr);
index 0f83dc3c7811bfe330420c7ddfc3c3844628f601..723eec3dc10ba9e1d7eb9f0f637e4cfc2b5a69b4 100644 (file)
@@ -82,7 +82,7 @@ extern void linux_displaced_step_restore_all_in_ptid (inferior *parent_inf,
                                                      ptid_t ptid);
 
 extern void linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
-                           bool supports_displaced_step);
+                           int num_disp_step_buffers);
 
 extern int linux_is_uclinux (void);
 
index 961d54a2ca261dc618070100939d8d1ca33114d3..0a1ff780d8c5012e8aa913d80ff77f26012797b2 100644 (file)
@@ -449,7 +449,7 @@ static void
 m32r_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Since EVB register is not available for native debug, we reduce
      the number of registers.  */
index 509333558ec93f94fc860a9a14ff3a0614a12847..f057915965f97609afa50856443756857d300614 100644 (file)
@@ -385,7 +385,7 @@ m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   tdep->jb_pc = M68K_LINUX_JB_PC;
   tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;
index 2a91e1bb39a876acff800bf53956f772ba65e587..54f89ec037779fdde37ea2bcb90247a9398592dd 100644 (file)
@@ -117,7 +117,7 @@ static void
 microblaze_linux_init_abi (struct gdbarch_info info,
                           struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   set_gdbarch_memory_remove_breakpoint (gdbarch,
                                        microblaze_linux_memory_remove_breakpoint);
index 9ca59e5b296b3b4b8ad2704b20e8b736a67179f8..ed95c22008412ba95f7c520dd6359ee61908442d 100644 (file)
@@ -1531,7 +1531,7 @@ mips_linux_init_abi (struct gdbarch_info info,
   enum mips_abi abi = mips_abi (gdbarch);
   struct tdesc_arch_data *tdesc_data = info.tdesc_data;
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Get the syscall number from the arch's register.  */
   set_gdbarch_get_syscall_number (gdbarch, mips_linux_get_syscall_number);
index 27645b1260c858e527cca0f389aad69765fc44f7..f7586bf3eae98e8a0eb3363bed72c2c0dadc8460 100644 (file)
@@ -704,7 +704,7 @@ am33_linux_sigframe_cache_init (const struct tramp_frame *self,
 static void
 am33_linux_init_osabi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   set_gdbarch_iterate_over_regset_sections
     (gdbarch, am33_iterate_over_regset_sections);
index b5c12852c70565e8f45904164d59b2d4b74e6230..0a28c9cca6d6faefd78f2d636e45acbca849c191 100644 (file)
@@ -219,7 +219,7 @@ nios2_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Shared library handling.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
index 33ddd10e85f377f3b9a8541e0881215ff40eeff8..2779fd0d1e61b73be3787c235ae741c0f06aa1e9 100644 (file)
@@ -140,7 +140,7 @@ or1k_linux_sigframe_init (const struct tramp_frame *self,
 static void
 or1k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   set_solib_svr4_fetch_link_map_offsets (gdbarch,
                                         svr4_ilp32_fetch_link_map_offsets);
index e6c10dd83db512392f6487ab8e66cb2c63238086..57bdd2d7a7235c20f74466be0d708783c61ec1de 100644 (file)
@@ -1993,7 +1993,7 @@ ppc_linux_init_abi (struct gdbarch_info info,
   static const char *const stap_register_indirection_suffixes[] = { ")",
                                                                    NULL };
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
      128-bit, they can be either IBM long double or IEEE quad long double.
index a2238ad786eb64de26384757c4f15f17cd0b4ba9..623c7d9382cce6dbb3199b9b8049c796bbd2a5fc 100644 (file)
@@ -159,7 +159,7 @@ riscv_linux_sigframe_init (const struct tramp_frame *self,
 static void
 riscv_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   set_gdbarch_software_single_step (gdbarch, riscv_software_single_step);
 
index 1a7c7fcb9f169ffe4b6b66dabe2565929eace8cd..235abd873f7288d715ec4c56df6deb4dbc862157 100644 (file)
@@ -160,7 +160,7 @@ struct ppc_inferior_data
   /* This is an optional in case we add more fields to ppc_inferior_data, we
      don't want it instantiated as soon as we get the ppc_inferior_data for an
      inferior.  */
-  gdb::optional<displaced_step_buffer> disp_step_buf;
+  gdb::optional<displaced_step_buffers> disp_step_buf;
 };
 
 static inferior_key<ppc_inferior_data> ppc_inferior_data_key;
index 14e92d2c6f33ba967d4420ee4a9cfcad6bddded5..8588d046bd6b15fa8f60f6096c0c796b8a271e04 100644 (file)
@@ -1119,7 +1119,7 @@ s390_linux_init_abi_any (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   tdep->s390_syscall_record = s390_linux_syscall_record;
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Register handling.  */
   set_gdbarch_core_read_description (gdbarch, s390_core_read_description);
index b7c66b70294e3df55a3f5c94315de540753d9ab1..84bcd3000694af295287911ebd20a452b8cc9698 100644 (file)
@@ -184,7 +184,7 @@ static struct tramp_frame sh_linux_rt_sigreturn_tramp_frame = {
 static void
 sh_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* GNU/Linux uses SVR4-style shared libraries.  */
   set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
index 3dbc65ca24df3a5c41b81bdbd67cbff63993acab..71759e19fa825768fd194b65381c5823fd9400c1 100644 (file)
@@ -422,7 +422,7 @@ sparc32_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   tdep->gregset = &sparc32_linux_gregset;
   tdep->sizeof_gregset = 152;
index 10a6eb527785142a2563e09ba58f51ff99f2b4bf..fe1b276bc4e83f9a1a68fe56c8f21b35dcd39484 100644 (file)
@@ -365,7 +365,7 @@ sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   tdep->gregset = &sparc64_linux_gregset;
   tdep->sizeof_gregset = 288;
index 5a8d7c7f8258b860f59cebe1b53b46ac2709b1f5..7820e2da5a0026014cce96660ef9b598b35f7cb0 100644 (file)
@@ -167,7 +167,7 @@ tic6x_uclinux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   /* Shared library handling.  */
   set_solib_ops (gdbarch, &dsbt_so_ops);
index 14cfafe33dec0d22018bf305e8d9701ab9b42157..37c0790a19098c694c9ab0da5046b22e5cc8aa9b 100644 (file)
@@ -111,7 +111,7 @@ tilegx_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   int arch_size = gdbarch_addr_bit (gdbarch);
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   tramp_frame_prepend_unwinder (gdbarch, &tilegx_linux_rt_sigframe);
 
index c2aeb8e9397b7df9eaaf60dbd97835103e4ec175..fccac7d49fc3b0e8900bafd38c074df8ce2daf07 100644 (file)
@@ -110,7 +110,7 @@ xtensa_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
       set_gdbarch_num_pseudo_regs (gdbarch, tdep->num_pseudo_regs);
     }
 
-  linux_init_abi (info, gdbarch, false);
+  linux_init_abi (info, gdbarch, 0);
 
   set_solib_svr4_fetch_link_map_offsets
     (gdbarch, svr4_ilp32_fetch_link_map_offsets);