*** empty log message ***
[deliverable/binutils-gdb.git] / gdb / bsd-kvm.c
index 083bc92c2977d8cca58cf5e54d356eba7989ddff..c7d6c9d9572eb344fd493948de5932fb7e77b920 100644 (file)
@@ -1,12 +1,13 @@
 /* BSD Kernel Data Access Library (libkvm) interface.
 
 /* BSD Kernel Data Access Library (libkvm) interface.
 
-   Copyright 2004 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -15,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "cli/cli-cmds.h"
 
 #include "defs.h"
 #include "cli/cli-cmds.h"
 #include "target.h"
 #include "value.h"
 #include "gdbcore.h"           /* for get_exec_file */
 #include "target.h"
 #include "value.h"
 #include "gdbcore.h"           /* for get_exec_file */
+#include "gdbthread.h"
 
 #include "gdb_assert.h"
 #include <fcntl.h>
 #include <kvm.h>
 
 #include "gdb_assert.h"
 #include <fcntl.h>
 #include <kvm.h>
+#ifdef HAVE_NLIST_H
 #include <nlist.h>
 #include <nlist.h>
+#endif
+#include <paths.h>
 #include "readline/readline.h"
 #include <sys/param.h>
 #include <sys/proc.h>
 #include "readline/readline.h"
 #include <sys/param.h>
 #include <sys/proc.h>
 
 #include "bsd-kvm.h"
 
 
 #include "bsd-kvm.h"
 
+/* Kernel memory device file.  */
+static const char *bsd_kvm_corefile;
+
 /* Kernel memory interface descriptor.  */
 /* Kernel memory interface descriptor.  */
-kvm_t *core_kd;
+static kvm_t *core_kd;
 
 /* Address of process control block.  */
 
 /* Address of process control block.  */
-struct pcb *bsd_kvm_paddr;
+static struct pcb *bsd_kvm_paddr;
 
 /* Pointer to architecture-specific function that reconstructs the
    register state from PCB and supplies it to REGCACHE.  */
 
 /* Pointer to architecture-specific function that reconstructs the
    register state from PCB and supplies it to REGCACHE.  */
-int (*bsd_kvm_supply_pcb)(struct regcache *regcache, struct pcb *pcb);
+static int (*bsd_kvm_supply_pcb)(struct regcache *regcache, struct pcb *pcb);
 
 /* Target ops for libkvm interface.  */
 
 /* Target ops for libkvm interface.  */
-struct target_ops bsd_kvm_ops;
+static struct target_ops bsd_kvm_ops;
+
+/* This is the ptid we use while we're connected to kvm.  The kvm
+   target currently doesn't export any view of the running processes,
+   so this represents the kernel task.  */
+static ptid_t bsd_kvm_ptid;
 
 static void
 bsd_kvm_open (char *filename, int from_tty)
 
 static void
 bsd_kvm_open (char *filename, int from_tty)
@@ -68,26 +79,30 @@ bsd_kvm_open (char *filename, int from_tty)
       filename = tilde_expand (filename);
       if (filename[0] != '/')
        {
       filename = tilde_expand (filename);
       if (filename[0] != '/')
        {
-         temp = concat (current_directory, "/", filename, NULL);
+         temp = concat (current_directory, "/", filename, (char *)NULL);
          xfree (filename);
          filename = temp;
        }
     }
 
   execfile = get_exec_file (0);
          xfree (filename);
          filename = temp;
        }
     }
 
   execfile = get_exec_file (0);
-  temp_kd = kvm_openfiles (execfile, filename, NULL, O_RDONLY, errbuf);
+  temp_kd = kvm_openfiles (execfile, filename, NULL,
+                          write_files ? O_RDWR : O_RDONLY, errbuf);
   if (temp_kd == NULL)
   if (temp_kd == NULL)
-    error ("%s", errbuf);
+    error (("%s"), errbuf);
 
 
+  bsd_kvm_corefile = filename;
   unpush_target (&bsd_kvm_ops);
   core_kd = temp_kd;
   push_target (&bsd_kvm_ops);
 
   unpush_target (&bsd_kvm_ops);
   core_kd = temp_kd;
   push_target (&bsd_kvm_ops);
 
-  target_fetch_registers (-1);
+  add_thread_silent (bsd_kvm_ptid);
+  inferior_ptid = bsd_kvm_ptid;
+
+  target_fetch_registers (get_current_regcache (), -1);
 
 
-  flush_cached_frames ();
-  select_frame (get_current_frame ());
-  print_stack_frame (get_selected_frame (), -1, 1);
+  reinit_frame_cache ();
+  print_stack_frame (get_selected_frame (NULL), -1, 1);
 }
 
 static void
 }
 
 static void
@@ -96,46 +111,76 @@ bsd_kvm_close (int quitting)
   if (core_kd)
     {
       if (kvm_close (core_kd) == -1)
   if (core_kd)
     {
       if (kvm_close (core_kd) == -1)
-       warning ("%s", kvm_geterr(core_kd));
+       warning (("%s"), kvm_geterr(core_kd));
       core_kd = NULL;
     }
       core_kd = NULL;
     }
+
+  inferior_ptid = null_ptid;
+  delete_thread_silent (bsd_kvm_ptid);
 }
 
 }
 
-static int
-bsd_kvm_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
-                   int write, struct mem_attrib *attrib,
-                   struct target_ops *ops)
+static LONGEST
+bsd_kvm_xfer_memory (CORE_ADDR addr, ULONGEST len,
+                    gdb_byte *readbuf, const gdb_byte *writebuf)
 {
 {
-  if (write)
-    return kvm_write (core_kd, memaddr, myaddr, len);
-  else
-    return kvm_read (core_kd, memaddr, myaddr, len);
+  ssize_t nbytes = len;
 
 
-  return -1;
+  if (readbuf)
+    nbytes = kvm_read (core_kd, addr, readbuf, nbytes);
+  if (writebuf && nbytes > 0)
+    nbytes = kvm_write (core_kd, addr, writebuf, nbytes);
+  return nbytes;
+}
+
+static LONGEST
+bsd_kvm_xfer_partial (struct target_ops *ops, enum target_object object,
+                     const char *annex, gdb_byte *readbuf,
+                     const gdb_byte *writebuf,
+                     ULONGEST offset, LONGEST len)
+{
+  switch (object)
+    {
+    case TARGET_OBJECT_MEMORY:
+      return bsd_kvm_xfer_memory (offset, len, readbuf, writebuf);
+
+    default:
+      return -1;
+    }
+}
+
+static void
+bsd_kvm_files_info (struct target_ops *ops)
+{
+  if (bsd_kvm_corefile && strcmp (bsd_kvm_corefile, _PATH_MEM) != 0)
+    printf_filtered (_("\tUsing the kernel crash dump %s.\n"),
+                    bsd_kvm_corefile);
+  else
+    printf_filtered (_("\tUsing the currently running kernel.\n"));
 }
 
 /* Fetch process control block at address PADDR.  */
 
 static int
 }
 
 /* Fetch process control block at address PADDR.  */
 
 static int
-bsd_kvm_fetch_pcb (struct pcb *paddr)
+bsd_kvm_fetch_pcb (struct regcache *regcache, struct pcb *paddr)
 {
   struct pcb pcb;
 
   if (kvm_read (core_kd, (unsigned long) paddr, &pcb, sizeof pcb) == -1)
 {
   struct pcb pcb;
 
   if (kvm_read (core_kd, (unsigned long) paddr, &pcb, sizeof pcb) == -1)
-    error ("%s", kvm_geterr (core_kd));
+    error (("%s"), kvm_geterr (core_kd));
 
   gdb_assert (bsd_kvm_supply_pcb);
 
   gdb_assert (bsd_kvm_supply_pcb);
-  return bsd_kvm_supply_pcb (current_regcache, &pcb);
+  return bsd_kvm_supply_pcb (regcache, &pcb);
 }
 
 static void
 }
 
 static void
-bsd_kvm_fetch_registers (int regnum)
+bsd_kvm_fetch_registers (struct target_ops *ops,
+                        struct regcache *regcache, int regnum)
 {
   struct nlist nl[2];
 
   if (bsd_kvm_paddr)
     {
 {
   struct nlist nl[2];
 
   if (bsd_kvm_paddr)
     {
-      bsd_kvm_fetch_pcb (bsd_kvm_paddr);
+      bsd_kvm_fetch_pcb (regcache, bsd_kvm_paddr);
       return;
     }
 
       return;
     }
 
@@ -145,13 +190,13 @@ bsd_kvm_fetch_registers (int regnum)
   nl[0].n_name = "_dumppcb";
 
   if (kvm_nlist (core_kd, nl) == -1)
   nl[0].n_name = "_dumppcb";
 
   if (kvm_nlist (core_kd, nl) == -1)
-    error ("%s", kvm_geterr (core_kd));
+    error (("%s"), kvm_geterr (core_kd));
 
   if (nl[0].n_value != 0)
     {
       /* Found dumppcb. If it contains a valid context, return
         immediately.  */
 
   if (nl[0].n_value != 0)
     {
       /* Found dumppcb. If it contains a valid context, return
         immediately.  */
-      if (bsd_kvm_fetch_pcb ((struct pcb *) nl[0].n_value))
+      if (bsd_kvm_fetch_pcb (regcache, (struct pcb *) nl[0].n_value))
        return;
     }
 
        return;
     }
 
@@ -163,7 +208,7 @@ bsd_kvm_fetch_registers (int regnum)
   nl[0].n_name = "_proc0paddr";
 
   if (kvm_nlist (core_kd, nl) == -1)
   nl[0].n_name = "_proc0paddr";
 
   if (kvm_nlist (core_kd, nl) == -1)
-    error ("%s", kvm_geterr (core_kd));
+    error (("%s"), kvm_geterr (core_kd));
 
   if (nl[0].n_value != 0)
     {
 
   if (nl[0].n_value != 0)
     {
@@ -171,9 +216,9 @@ bsd_kvm_fetch_registers (int regnum)
 
       /* Found proc0paddr.  */
       if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
 
       /* Found proc0paddr.  */
       if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
-       error ("%s", kvm_geterr (core_kd));
+       error (("%s"), kvm_geterr (core_kd));
 
 
-      bsd_kvm_fetch_pcb (paddr);
+      bsd_kvm_fetch_pcb (regcache, paddr);
       return;
     }
 
       return;
     }
 
@@ -187,7 +232,7 @@ bsd_kvm_fetch_registers (int regnum)
   nl[0].n_name = "_thread0";
 
   if (kvm_nlist (core_kd, nl) == -1)
   nl[0].n_name = "_thread0";
 
   if (kvm_nlist (core_kd, nl) == -1)
-    error ("%s", kvm_geterr (core_kd));
+    error (("%s"), kvm_geterr (core_kd));
 
   if (nl[0].n_value != 0)
     {
 
   if (nl[0].n_value != 0)
     {
@@ -196,14 +241,15 @@ bsd_kvm_fetch_registers (int regnum)
       /* Found thread0.  */
       nl[0].n_value += offsetof (struct thread, td_pcb);
       if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
       /* Found thread0.  */
       nl[0].n_value += offsetof (struct thread, td_pcb);
       if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
-       error ("%s", kvm_geterr (core_kd));
+       error (("%s"), kvm_geterr (core_kd));
 
 
-      bsd_kvm_fetch_pcb (paddr);
+      bsd_kvm_fetch_pcb (regcache, paddr);
       return;
     }
 #endif
 
       return;
     }
 #endif
 
-  error ("Cannot find a valid PCB");
+  /* i18n: PCB == "Process Control Block" */
+  error (_("Cannot find a valid PCB"));
 }
 \f
 
 }
 \f
 
@@ -224,10 +270,10 @@ bsd_kvm_proc_cmd (char *arg, int fromtty)
   CORE_ADDR addr;
 
   if (arg == NULL)
   CORE_ADDR addr;
 
   if (arg == NULL)
-    error_no_arg ("proc address");
+    error_no_arg (_("proc address"));
 
   if (core_kd == NULL)
 
   if (core_kd == NULL)
-    error ("No kernel memory image.");
+    error (_("No kernel memory image."));
 
   addr = parse_and_eval_address (arg);
 #ifdef HAVE_STRUCT_LWP
 
   addr = parse_and_eval_address (arg);
 #ifdef HAVE_STRUCT_LWP
@@ -237,13 +283,12 @@ bsd_kvm_proc_cmd (char *arg, int fromtty)
 #endif
 
   if (kvm_read (core_kd, addr, &bsd_kvm_paddr, sizeof bsd_kvm_paddr) == -1)
 #endif
 
   if (kvm_read (core_kd, addr, &bsd_kvm_paddr, sizeof bsd_kvm_paddr) == -1)
-    error ("%s", kvm_geterr (core_kd));
+    error (("%s"), kvm_geterr (core_kd));
 
 
-  target_fetch_registers (-1);
+  target_fetch_registers (get_current_regcache (), -1);
 
 
-  flush_cached_frames ();
-  select_frame (get_current_frame ());
-  print_stack_frame (get_selected_frame (), -1, 1);
+  reinit_frame_cache ();
+  print_stack_frame (get_selected_frame (NULL), -1, 1);
 }
 
 #endif
 }
 
 #endif
@@ -252,18 +297,39 @@ static void
 bsd_kvm_pcb_cmd (char *arg, int fromtty)
 {
   if (arg == NULL)
 bsd_kvm_pcb_cmd (char *arg, int fromtty)
 {
   if (arg == NULL)
-    error_no_arg ("pcb address");
+    /* i18n: PCB == "Process Control Block" */
+    error_no_arg (_("pcb address"));
 
   if (core_kd == NULL)
 
   if (core_kd == NULL)
-    error ("No kernel memory image.");
+    error (_("No kernel memory image."));
+
+  bsd_kvm_paddr = (struct pcb *)(u_long) parse_and_eval_address (arg);
+
+  target_fetch_registers (get_current_regcache (), -1);
+
+  reinit_frame_cache ();
+  print_stack_frame (get_selected_frame (NULL), -1, 1);
+}
 
 
-  bsd_kvm_paddr = (struct pcb *) parse_and_eval_address (arg);
+static int
+bsd_kvm_thread_alive (struct target_ops *ops,
+                     ptid_t ptid)
+{
+  return 1;
+}
 
 
-  target_fetch_registers (-1);
+static char *
+bsd_kvm_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+  static char buf[64];
+  xsnprintf (buf, sizeof buf, "<kvm>");
+  return buf;
+}
 
 
-  flush_cached_frames ();
-  select_frame (get_current_frame ());
-  print_stack_frame (get_selected_frame (), -1, 1);
+static int
+bsd_kvm_return_one (struct target_ops *ops)
+{
+  return 1;
 }
 
 /* Add the libkvm interface to the list of all possible targets and
 }
 
 /* Add the libkvm interface to the list of all possible targets and
@@ -277,29 +343,49 @@ bsd_kvm_add_target (int (*supply_pcb)(struct regcache *, struct pcb *))
   bsd_kvm_supply_pcb = supply_pcb;
 
   bsd_kvm_ops.to_shortname = "kvm";
   bsd_kvm_supply_pcb = supply_pcb;
 
   bsd_kvm_ops.to_shortname = "kvm";
-  bsd_kvm_ops.to_longname = "Kernel memory interface";
-  bsd_kvm_ops.to_doc = "Use a kernel virtual memory image as a target.\n\
-Optionally specify the filename of a core dump.";
+  bsd_kvm_ops.to_longname = _("Kernel memory interface");
+  bsd_kvm_ops.to_doc = _("Use a kernel virtual memory image as a target.\n\
+Optionally specify the filename of a core dump.");
   bsd_kvm_ops.to_open = bsd_kvm_open;
   bsd_kvm_ops.to_close = bsd_kvm_close;
   bsd_kvm_ops.to_fetch_registers = bsd_kvm_fetch_registers;
   bsd_kvm_ops.to_open = bsd_kvm_open;
   bsd_kvm_ops.to_close = bsd_kvm_close;
   bsd_kvm_ops.to_fetch_registers = bsd_kvm_fetch_registers;
-  bsd_kvm_ops.to_xfer_memory = bsd_kvm_xfer_memory;
+  bsd_kvm_ops.to_xfer_partial = bsd_kvm_xfer_partial;
+  bsd_kvm_ops.to_files_info = bsd_kvm_files_info;
+  bsd_kvm_ops.to_thread_alive = bsd_kvm_thread_alive;
+  bsd_kvm_ops.to_pid_to_str = bsd_kvm_pid_to_str;
   bsd_kvm_ops.to_stratum = process_stratum;
   bsd_kvm_ops.to_stratum = process_stratum;
-  bsd_kvm_ops.to_has_memory = 1;
-  bsd_kvm_ops.to_has_stack = 1;
-  bsd_kvm_ops.to_has_registers = 1;
+  bsd_kvm_ops.to_has_memory = bsd_kvm_return_one;
+  bsd_kvm_ops.to_has_stack = bsd_kvm_return_one;
+  bsd_kvm_ops.to_has_registers = bsd_kvm_return_one;
   bsd_kvm_ops.to_magic = OPS_MAGIC;
 
   add_target (&bsd_kvm_ops);
   
   bsd_kvm_ops.to_magic = OPS_MAGIC;
 
   add_target (&bsd_kvm_ops);
   
-  add_prefix_cmd ("kvm", class_obscure, bsd_kvm_cmd, "\
-Generic command for manipulating the kernel memory interface.",
+  add_prefix_cmd ("kvm", class_obscure, bsd_kvm_cmd, _("\
+Generic command for manipulating the kernel memory interface."),
                  &bsd_kvm_cmdlist, "kvm ", 0, &cmdlist);
 
 #ifndef HAVE_STRUCT_THREAD_TD_PCB
   add_cmd ("proc", class_obscure, bsd_kvm_proc_cmd,
                  &bsd_kvm_cmdlist, "kvm ", 0, &cmdlist);
 
 #ifndef HAVE_STRUCT_THREAD_TD_PCB
   add_cmd ("proc", class_obscure, bsd_kvm_proc_cmd,
-          "Set current context from proc address", &bsd_kvm_cmdlist);
+          _("Set current context from proc address"), &bsd_kvm_cmdlist);
 #endif
   add_cmd ("pcb", class_obscure, bsd_kvm_pcb_cmd,
 #endif
   add_cmd ("pcb", class_obscure, bsd_kvm_pcb_cmd,
-          "Set current context from pcb address", &bsd_kvm_cmdlist);
+          /* i18n: PCB == "Process Control Block" */
+          _("Set current context from pcb address"), &bsd_kvm_cmdlist);
+
+  /* Some notes on the ptid usage on this target.
+
+     The pid field represents the kvm inferior instance.  Currently,
+     we don't support multiple kvm inferiors, but we start at 1
+     anyway.  The lwp field is set to != 0, in case the core wants to
+     refer to the whole kvm inferior with ptid(1,0,0).
+
+     If kvm is made to export running processes as gdb threads,
+     the following form can be used:
+     ptid (1, 1, 0) -> kvm inferior 1, in kernel
+     ptid (1, 1, 1) -> kvm inferior 1, process 1
+     ptid (1, 1, 2) -> kvm inferior 1, process 2
+     ptid (1, 1, n) -> kvm inferior 1, process n
+  */
+  bsd_kvm_ptid = ptid_build (1, 1, 0);
 }
 }
This page took 0.030245 seconds and 4 git commands to generate.