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