X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fbsd-kvm.c;h=365c166dfce8fccc192f3ee1f7f0f135433e40b4;hb=bfb1c7963b15b31073c9adf2d97ff1cf953ec99c;hp=45ce561951642d72f143fcbca0c698d8ae9e60a3;hpb=7f245d65f70913f51bfd1cb4f49822801ca6ecc9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/bsd-kvm.c b/gdb/bsd-kvm.c index 45ce561951..365c166dfc 100644 --- a/gdb/bsd-kvm.c +++ b/gdb/bsd-kvm.c @@ -1,12 +1,12 @@ /* BSD Kernel Data Access Library (libkvm) interface. - Copyright 2004 Free Software Foundation, Inc. + Copyright (C) 2004-2015 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 - 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, @@ -15,9 +15,7 @@ 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 . */ #include "defs.h" #include "cli/cli-cmds.h" @@ -27,11 +25,14 @@ #include "target.h" #include "value.h" #include "gdbcore.h" /* for get_exec_file */ +#include "gdbthread.h" -#include "gdb_assert.h" #include #include +#ifdef HAVE_NLIST_H #include +#endif +#include #include "readline/readline.h" #include #include @@ -39,103 +40,158 @@ #include "bsd-kvm.h" +/* Kernel memory device file. */ +static const char *bsd_kvm_corefile; + /* Kernel memory interface descriptor. */ -kvm_t *core_kd; +static kvm_t *core_kd; /* 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. */ -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. */ -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) +bsd_kvm_open (const char *arg, int from_tty) { char errbuf[_POSIX2_LINE_MAX]; char *execfile = NULL; kvm_t *temp_kd; + char *filename = NULL; target_preopen (from_tty); - if (filename) + if (arg) { char *temp; - filename = tilde_expand (filename); + filename = tilde_expand (arg); 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); - 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) - error ("%s", errbuf); + error (("%s"), errbuf); + bsd_kvm_corefile = filename; 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; - flush_cached_frames (); - select_frame (get_current_frame ()); - print_stack_frame (get_selected_frame (), -1, 1); + target_fetch_registers (get_current_regcache (), -1); + + reinit_frame_cache (); + print_stack_frame (get_selected_frame (NULL), 0, SRC_AND_LOC, 1); } static void -bsd_kvm_close (int quitting) +bsd_kvm_close (struct target_ops *self) { if (core_kd) { if (kvm_close (core_kd) == -1) - warning ("%s", kvm_geterr(core_kd)); + warning (("%s"), kvm_geterr(core_kd)); 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; + + if (readbuf) + nbytes = kvm_read (core_kd, addr, readbuf, nbytes); + if (writebuf && nbytes > 0) + nbytes = kvm_write (core_kd, addr, writebuf, nbytes); + return nbytes; +} - return -1; +static enum target_xfer_status +bsd_kvm_xfer_partial (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) +{ + switch (object) + { + case TARGET_OBJECT_MEMORY: + { + LONGEST ret = bsd_kvm_xfer_memory (offset, len, readbuf, writebuf); + + if (ret < 0) + return TARGET_XFER_E_IO; + else if (ret == 0) + return TARGET_XFER_EOF; + else + { + *xfered_len = (ULONGEST) ret; + return TARGET_XFER_OK; + } + } + + default: + return TARGET_XFER_E_IO; + } +} + +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 -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) - error ("%s", kvm_geterr (core_kd)); + error (("%s"), kvm_geterr (core_kd)); gdb_assert (bsd_kvm_supply_pcb); - return bsd_kvm_supply_pcb (current_regcache, &pcb); + return bsd_kvm_supply_pcb (regcache, &pcb); } 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) { - bsd_kvm_fetch_pcb (bsd_kvm_paddr); + bsd_kvm_fetch_pcb (regcache, bsd_kvm_paddr); return; } @@ -145,13 +201,13 @@ bsd_kvm_fetch_registers (int regnum) 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 + /* 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; } @@ -163,7 +219,7 @@ bsd_kvm_fetch_registers (int regnum) 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) { @@ -171,9 +227,9 @@ bsd_kvm_fetch_registers (int regnum) /* 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; } @@ -187,7 +243,7 @@ bsd_kvm_fetch_registers (int regnum) 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) { @@ -196,14 +252,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) - 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 - error ("Cannot find a valid PCB"); + /* i18n: PCB == "Process Control Block". */ + error (_("Cannot find a valid PCB")); } @@ -224,22 +281,25 @@ bsd_kvm_proc_cmd (char *arg, int fromtty) CORE_ADDR addr; if (arg == NULL) - error_no_arg ("proc address"); + error_no_arg (_("proc address")); 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 += offsetof (struct lwp, l_addr); +#else addr += offsetof (struct proc, p_addr); +#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), 0, SRC_AND_LOC, 1); } #endif @@ -248,18 +308,39 @@ static void 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) - 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), 0, SRC_AND_LOC, 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, ""); + 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 @@ -273,29 +354,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_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_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_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); - 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, - "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, - "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); }