xref: /openbsd-src/gnu/usr.bin/binutils/gdb/bsd-kvm.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
152ba75afSkettenis /* BSD Kernel Data Access Library (libkvm) interface.
252ba75afSkettenis 
352ba75afSkettenis    Copyright 2004 Free Software Foundation, Inc.
452ba75afSkettenis 
552ba75afSkettenis    This file is part of GDB.
652ba75afSkettenis 
752ba75afSkettenis    This program is free software; you can redistribute it and/or modify
852ba75afSkettenis    it under the terms of the GNU General Public License as published by
952ba75afSkettenis    the Free Software Foundation; either version 2 of the License, or
1052ba75afSkettenis    (at your option) any later version.
1152ba75afSkettenis 
1252ba75afSkettenis    This program is distributed in the hope that it will be useful,
1352ba75afSkettenis    but WITHOUT ANY WARRANTY; without even the implied warranty of
1452ba75afSkettenis    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1552ba75afSkettenis    GNU General Public License for more details.
1652ba75afSkettenis 
1752ba75afSkettenis    You should have received a copy of the GNU General Public License
1852ba75afSkettenis    along with this program; if not, write to the Free Software
1952ba75afSkettenis    Foundation, Inc., 59 Temple Place - Suite 330,
2052ba75afSkettenis    Boston, MA 02111-1307, USA.  */
2152ba75afSkettenis 
2252ba75afSkettenis #include "defs.h"
231505a8a8Skettenis #include "cli/cli-cmds.h"
241505a8a8Skettenis #include "command.h"
2552ba75afSkettenis #include "frame.h"
2652ba75afSkettenis #include "regcache.h"
2752ba75afSkettenis #include "target.h"
281505a8a8Skettenis #include "value.h"
29*63addd46Skettenis #include "gdbcore.h"		/* for get_exec_file */
3052ba75afSkettenis 
3152ba75afSkettenis #include "gdb_assert.h"
3252ba75afSkettenis #include <fcntl.h>
3352ba75afSkettenis #include <kvm.h>
34*63addd46Skettenis #ifdef HAVE_NLIST_H
3552ba75afSkettenis #include <nlist.h>
36*63addd46Skettenis #endif
3752ba75afSkettenis #include "readline/readline.h"
3852ba75afSkettenis #include <sys/param.h>
391505a8a8Skettenis #include <sys/proc.h>
4052ba75afSkettenis #include <sys/user.h>
4152ba75afSkettenis 
4252ba75afSkettenis #include "bsd-kvm.h"
4352ba75afSkettenis 
4452ba75afSkettenis /* Kernel memory interface descriptor.  */
4552ba75afSkettenis kvm_t *core_kd;
4652ba75afSkettenis 
4752ba75afSkettenis /* Address of process control block.  */
4852ba75afSkettenis struct pcb *bsd_kvm_paddr;
4952ba75afSkettenis 
501505a8a8Skettenis /* Pointer to architecture-specific function that reconstructs the
511505a8a8Skettenis    register state from PCB and supplies it to REGCACHE.  */
521505a8a8Skettenis int (*bsd_kvm_supply_pcb)(struct regcache *regcache, struct pcb *pcb);
531505a8a8Skettenis 
5452ba75afSkettenis /* Target ops for libkvm interface.  */
5552ba75afSkettenis struct target_ops bsd_kvm_ops;
5652ba75afSkettenis 
5752ba75afSkettenis static void
bsd_kvm_open(char * filename,int from_tty)5852ba75afSkettenis bsd_kvm_open (char *filename, int from_tty)
5952ba75afSkettenis {
6052ba75afSkettenis   char errbuf[_POSIX2_LINE_MAX];
6152ba75afSkettenis   char *execfile = NULL;
6252ba75afSkettenis   kvm_t *temp_kd;
6352ba75afSkettenis 
6452ba75afSkettenis   target_preopen (from_tty);
6552ba75afSkettenis 
6652ba75afSkettenis   if (filename)
6752ba75afSkettenis     {
6852ba75afSkettenis       char *temp;
6952ba75afSkettenis 
7052ba75afSkettenis       filename = tilde_expand (filename);
7152ba75afSkettenis       if (filename[0] != '/')
7252ba75afSkettenis 	{
7352ba75afSkettenis 	  temp = concat (current_directory, "/", filename, NULL);
7452ba75afSkettenis 	  xfree (filename);
7552ba75afSkettenis 	  filename = temp;
7652ba75afSkettenis 	}
7752ba75afSkettenis     }
7852ba75afSkettenis 
79*63addd46Skettenis   execfile = get_exec_file (0);
8052ba75afSkettenis   temp_kd = kvm_openfiles (execfile, filename, NULL, O_RDONLY, errbuf);
8152ba75afSkettenis   if (temp_kd == NULL)
8252ba75afSkettenis     error ("%s", errbuf);
8352ba75afSkettenis 
8452ba75afSkettenis   unpush_target (&bsd_kvm_ops);
8552ba75afSkettenis   core_kd = temp_kd;
8652ba75afSkettenis   push_target (&bsd_kvm_ops);
8752ba75afSkettenis 
8852ba75afSkettenis   target_fetch_registers (-1);
8952ba75afSkettenis 
9052ba75afSkettenis   flush_cached_frames ();
9152ba75afSkettenis   select_frame (get_current_frame ());
9252ba75afSkettenis   print_stack_frame (get_selected_frame (), -1, 1);
9352ba75afSkettenis }
9452ba75afSkettenis 
9552ba75afSkettenis static void
bsd_kvm_close(int quitting)9652ba75afSkettenis bsd_kvm_close (int quitting)
9752ba75afSkettenis {
9852ba75afSkettenis   if (core_kd)
9952ba75afSkettenis     {
10052ba75afSkettenis       if (kvm_close (core_kd) == -1)
10152ba75afSkettenis 	warning ("%s", kvm_geterr(core_kd));
10252ba75afSkettenis       core_kd = NULL;
10352ba75afSkettenis     }
10452ba75afSkettenis }
10552ba75afSkettenis 
10652ba75afSkettenis static int
bsd_kvm_xfer_memory(CORE_ADDR memaddr,char * myaddr,int len,int write,struct mem_attrib * attrib,struct target_ops * ops)10752ba75afSkettenis bsd_kvm_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len,
10852ba75afSkettenis 		    int write, struct mem_attrib *attrib,
10952ba75afSkettenis 		    struct target_ops *ops)
11052ba75afSkettenis {
11152ba75afSkettenis   if (write)
11252ba75afSkettenis     return kvm_write (core_kd, memaddr, myaddr, len);
11352ba75afSkettenis   else
11452ba75afSkettenis     return kvm_read (core_kd, memaddr, myaddr, len);
11552ba75afSkettenis 
11652ba75afSkettenis   return -1;
11752ba75afSkettenis }
11852ba75afSkettenis 
1191505a8a8Skettenis /* Fetch process control block at address PADDR.  */
1201505a8a8Skettenis 
12152ba75afSkettenis static int
bsd_kvm_fetch_pcb(struct pcb * paddr)12252ba75afSkettenis bsd_kvm_fetch_pcb (struct pcb *paddr)
12352ba75afSkettenis {
12452ba75afSkettenis   struct pcb pcb;
12552ba75afSkettenis 
12652ba75afSkettenis   if (kvm_read (core_kd, (unsigned long) paddr, &pcb, sizeof pcb) == -1)
12752ba75afSkettenis     error ("%s", kvm_geterr (core_kd));
12852ba75afSkettenis 
12952ba75afSkettenis   gdb_assert (bsd_kvm_supply_pcb);
13052ba75afSkettenis   return bsd_kvm_supply_pcb (current_regcache, &pcb);
13152ba75afSkettenis }
13252ba75afSkettenis 
13352ba75afSkettenis static void
bsd_kvm_fetch_registers(int regnum)13452ba75afSkettenis bsd_kvm_fetch_registers (int regnum)
13552ba75afSkettenis {
13652ba75afSkettenis   struct nlist nl[2];
13752ba75afSkettenis 
13852ba75afSkettenis   if (bsd_kvm_paddr)
1391505a8a8Skettenis     {
14052ba75afSkettenis       bsd_kvm_fetch_pcb (bsd_kvm_paddr);
1411505a8a8Skettenis       return;
1421505a8a8Skettenis     }
14352ba75afSkettenis 
14452ba75afSkettenis   /* On dumping core, BSD kernels store the faulting context (PCB)
14552ba75afSkettenis      in the variable "dumppcb".  */
14652ba75afSkettenis   memset (nl, 0, sizeof nl);
14752ba75afSkettenis   nl[0].n_name = "_dumppcb";
14852ba75afSkettenis 
14952ba75afSkettenis   if (kvm_nlist (core_kd, nl) == -1)
15052ba75afSkettenis     error ("%s", kvm_geterr (core_kd));
15152ba75afSkettenis 
15252ba75afSkettenis   if (nl[0].n_value != 0)
15352ba75afSkettenis     {
15452ba75afSkettenis       /* Found dumppcb. If it contains a valid context, return
15552ba75afSkettenis 	 immediately.  */
15652ba75afSkettenis       if (bsd_kvm_fetch_pcb ((struct pcb *) nl[0].n_value))
15752ba75afSkettenis 	return;
15852ba75afSkettenis     }
15952ba75afSkettenis 
16052ba75afSkettenis   /* Traditional BSD kernels have a process proc0 that should always
16152ba75afSkettenis      be present.  The address of proc0's PCB is stored in the variable
16252ba75afSkettenis      "proc0paddr".  */
16352ba75afSkettenis 
16452ba75afSkettenis   memset (nl, 0, sizeof nl);
16552ba75afSkettenis   nl[0].n_name = "_proc0paddr";
16652ba75afSkettenis 
16752ba75afSkettenis   if (kvm_nlist (core_kd, nl) == -1)
16852ba75afSkettenis     error ("%s", kvm_geterr (core_kd));
16952ba75afSkettenis 
17052ba75afSkettenis   if (nl[0].n_value != 0)
17152ba75afSkettenis     {
17252ba75afSkettenis       struct pcb *paddr;
17352ba75afSkettenis 
17452ba75afSkettenis       /* Found proc0paddr.  */
17552ba75afSkettenis       if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
17652ba75afSkettenis 	error ("%s", kvm_geterr (core_kd));
17752ba75afSkettenis 
17852ba75afSkettenis       bsd_kvm_fetch_pcb (paddr);
17952ba75afSkettenis       return;
18052ba75afSkettenis     }
18152ba75afSkettenis 
18252ba75afSkettenis #ifdef HAVE_STRUCT_THREAD_TD_PCB
18352ba75afSkettenis   /* In FreeBSD kernels for 5.0-RELEASE and later, the PCB no longer
18452ba75afSkettenis      lives in `struct proc' but in `struct thread'.  The `struct
18552ba75afSkettenis      thread' for the initial thread for proc0 can be found in the
18652ba75afSkettenis      variable "thread0".  */
18752ba75afSkettenis 
18852ba75afSkettenis   memset (nl, 0, sizeof nl);
18952ba75afSkettenis   nl[0].n_name = "_thread0";
19052ba75afSkettenis 
19152ba75afSkettenis   if (kvm_nlist (core_kd, nl) == -1)
19252ba75afSkettenis     error ("%s", kvm_geterr (core_kd));
19352ba75afSkettenis 
19452ba75afSkettenis   if (nl[0].n_value != 0)
19552ba75afSkettenis     {
19652ba75afSkettenis       struct pcb *paddr;
19752ba75afSkettenis 
19852ba75afSkettenis       /* Found thread0.  */
1991505a8a8Skettenis       nl[0].n_value += offsetof (struct thread, td_pcb);
2001505a8a8Skettenis       if (kvm_read (core_kd, nl[0].n_value, &paddr, sizeof paddr) == -1)
20152ba75afSkettenis 	error ("%s", kvm_geterr (core_kd));
20252ba75afSkettenis 
20352ba75afSkettenis       bsd_kvm_fetch_pcb (paddr);
20452ba75afSkettenis       return;
20552ba75afSkettenis     }
20652ba75afSkettenis #endif
20752ba75afSkettenis 
20852ba75afSkettenis   error ("Cannot find a valid PCB");
20952ba75afSkettenis }
2101505a8a8Skettenis 
2111505a8a8Skettenis 
2121505a8a8Skettenis /* Kernel memory interface commands.  */
2131505a8a8Skettenis struct cmd_list_element *bsd_kvm_cmdlist;
2141505a8a8Skettenis 
2151505a8a8Skettenis static void
bsd_kvm_cmd(char * arg,int fromtty)2161505a8a8Skettenis bsd_kvm_cmd (char *arg, int fromtty)
2171505a8a8Skettenis {
2181505a8a8Skettenis   /* ??? Should this become an alias for "target kvm"?  */
2191505a8a8Skettenis }
2201505a8a8Skettenis 
2211505a8a8Skettenis #ifndef HAVE_STRUCT_THREAD_TD_PCB
2221505a8a8Skettenis 
2231505a8a8Skettenis static void
bsd_kvm_proc_cmd(char * arg,int fromtty)2241505a8a8Skettenis bsd_kvm_proc_cmd (char *arg, int fromtty)
2251505a8a8Skettenis {
2261505a8a8Skettenis   CORE_ADDR addr;
2271505a8a8Skettenis 
2281505a8a8Skettenis   if (arg == NULL)
2291505a8a8Skettenis     error_no_arg ("proc address");
2301505a8a8Skettenis 
2311505a8a8Skettenis   if (core_kd == NULL)
2321505a8a8Skettenis     error ("No kernel memory image.");
2331505a8a8Skettenis 
2341505a8a8Skettenis   addr = parse_and_eval_address (arg);
235*63addd46Skettenis #ifdef HAVE_STRUCT_LWP
236*63addd46Skettenis   addr += offsetof (struct lwp, l_addr);
237*63addd46Skettenis #else
2381505a8a8Skettenis   addr += offsetof (struct proc, p_addr);
239*63addd46Skettenis #endif
2401505a8a8Skettenis 
2411505a8a8Skettenis   if (kvm_read (core_kd, addr, &bsd_kvm_paddr, sizeof bsd_kvm_paddr) == -1)
2421505a8a8Skettenis     error ("%s", kvm_geterr (core_kd));
2431505a8a8Skettenis 
2441505a8a8Skettenis   target_fetch_registers (-1);
2451505a8a8Skettenis 
2461505a8a8Skettenis   flush_cached_frames ();
2471505a8a8Skettenis   select_frame (get_current_frame ());
2481505a8a8Skettenis   print_stack_frame (get_selected_frame (), -1, 1);
2491505a8a8Skettenis }
2501505a8a8Skettenis 
2511505a8a8Skettenis #endif
2521505a8a8Skettenis 
2531505a8a8Skettenis static void
bsd_kvm_pcb_cmd(char * arg,int fromtty)2541505a8a8Skettenis bsd_kvm_pcb_cmd (char *arg, int fromtty)
2551505a8a8Skettenis {
2561505a8a8Skettenis   if (arg == NULL)
2571505a8a8Skettenis     error_no_arg ("pcb address");
2581505a8a8Skettenis 
2591505a8a8Skettenis   if (core_kd == NULL)
2601505a8a8Skettenis     error ("No kernel memory image.");
2611505a8a8Skettenis 
2621505a8a8Skettenis   bsd_kvm_paddr = (struct pcb *) parse_and_eval_address (arg);
2631505a8a8Skettenis 
2641505a8a8Skettenis   target_fetch_registers (-1);
2651505a8a8Skettenis 
2661505a8a8Skettenis   flush_cached_frames ();
2671505a8a8Skettenis   select_frame (get_current_frame ());
2681505a8a8Skettenis   print_stack_frame (get_selected_frame (), -1, 1);
2691505a8a8Skettenis }
2701505a8a8Skettenis 
2711505a8a8Skettenis /* Add the libkvm interface to the list of all possible targets and
2721505a8a8Skettenis    register CUPPLY_PCB as the architecture-specific process control
2731505a8a8Skettenis    block interpreter.  */
27452ba75afSkettenis 
27552ba75afSkettenis void
bsd_kvm_add_target(int (* supply_pcb)(struct regcache *,struct pcb *))2761505a8a8Skettenis bsd_kvm_add_target (int (*supply_pcb)(struct regcache *, struct pcb *))
27752ba75afSkettenis {
2781505a8a8Skettenis   gdb_assert (bsd_kvm_supply_pcb == NULL);
2791505a8a8Skettenis   bsd_kvm_supply_pcb = supply_pcb;
2801505a8a8Skettenis 
28152ba75afSkettenis   bsd_kvm_ops.to_shortname = "kvm";
28252ba75afSkettenis   bsd_kvm_ops.to_longname = "Kernel memory interface";
2831505a8a8Skettenis   bsd_kvm_ops.to_doc = "Use a kernel virtual memory image as a target.\n\
2841505a8a8Skettenis Optionally specify the filename of a core dump.";
28552ba75afSkettenis   bsd_kvm_ops.to_open = bsd_kvm_open;
28652ba75afSkettenis   bsd_kvm_ops.to_close = bsd_kvm_close;
28752ba75afSkettenis   bsd_kvm_ops.to_fetch_registers = bsd_kvm_fetch_registers;
288*63addd46Skettenis   bsd_kvm_ops.deprecated_xfer_memory = bsd_kvm_xfer_memory;
28952ba75afSkettenis   bsd_kvm_ops.to_stratum = process_stratum;
29052ba75afSkettenis   bsd_kvm_ops.to_has_memory = 1;
29152ba75afSkettenis   bsd_kvm_ops.to_has_stack = 1;
29252ba75afSkettenis   bsd_kvm_ops.to_has_registers = 1;
29352ba75afSkettenis   bsd_kvm_ops.to_magic = OPS_MAGIC;
29452ba75afSkettenis 
29552ba75afSkettenis   add_target (&bsd_kvm_ops);
2961505a8a8Skettenis 
2971505a8a8Skettenis   add_prefix_cmd ("kvm", class_obscure, bsd_kvm_cmd, "\
2981505a8a8Skettenis Generic command for manipulating the kernel memory interface.",
2991505a8a8Skettenis 		  &bsd_kvm_cmdlist, "kvm ", 0, &cmdlist);
3001505a8a8Skettenis 
3011505a8a8Skettenis #ifndef HAVE_STRUCT_THREAD_TD_PCB
3021505a8a8Skettenis   add_cmd ("proc", class_obscure, bsd_kvm_proc_cmd,
3031505a8a8Skettenis 	   "Set current context from proc address", &bsd_kvm_cmdlist);
3041505a8a8Skettenis #endif
3051505a8a8Skettenis   add_cmd ("pcb", class_obscure, bsd_kvm_pcb_cmd,
3061505a8a8Skettenis 	   "Set current context from pcb address", &bsd_kvm_cmdlist);
30752ba75afSkettenis }
308