5ee17cb3c6
Ada programming knowledgeable version of gdb53 PR: ports/56371 Submitted by: John R. Shannon <john@johnrshannon.com>
759 lines
20 KiB
C
759 lines
20 KiB
C
--- gdb/kvm-fbsd.c Fri Jan 3 08:57:23 2003
|
||
+++ gdb/kvm-fbsd.c Fri Jan 3 08:57:20 2003
|
||
@@ -0,0 +1,756 @@
|
||
+/* Kernel core dump functions below target vector, for GDB.
|
||
+ Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995
|
||
+ 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
|
||
+(at your option) any later version.
|
||
+
|
||
+This program is distributed in the hope that it will be useful,
|
||
+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
+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.
|
||
+*/
|
||
+
|
||
+/* $FreeBSD: /tmp/pcvs/ports/devel/gdb53-act/files/Attic/patch-gdb_kvm-fbsd.c,v 1.1 2003-09-27 07:38:23 edwin Exp $ */
|
||
+
|
||
+/*
|
||
+ * This works like "remote" but, you use it like this:
|
||
+ * target kcore /dev/mem
|
||
+ * or
|
||
+ * target kcore /var/crash/host/core.0
|
||
+ *
|
||
+ * This way makes it easy to short-circut the whole bfd monster,
|
||
+ * and direct the inferior stuff to our libkvm implementation.
|
||
+ *
|
||
+ */
|
||
+
|
||
+#include <sys/param.h>
|
||
+#include <sys/time.h>
|
||
+#include <sys/proc.h>
|
||
+#include <sys/user.h>
|
||
+#include <ctype.h>
|
||
+#include <errno.h>
|
||
+#include <signal.h>
|
||
+#include <fcntl.h>
|
||
+#include <kvm.h>
|
||
+#include <sys/sysctl.h>
|
||
+#include <paths.h>
|
||
+#include <readline/tilde.h>
|
||
+#include <machine/frame.h>
|
||
+
|
||
+#include "defs.h"
|
||
+#include "gdb_string.h"
|
||
+#include "frame.h" /* required by inferior.h */
|
||
+#include "inferior.h"
|
||
+#include "symtab.h"
|
||
+#include "symfile.h"
|
||
+#include "objfiles.h"
|
||
+#include "command.h"
|
||
+#include "bfd.h"
|
||
+#include "target.h"
|
||
+#include "gdbcore.h"
|
||
+#include "regcache.h"
|
||
+
|
||
+#if __FreeBSD_version >= 500032
|
||
+static void
|
||
+kcore_files_info (struct target_ops *);
|
||
+
|
||
+static void
|
||
+kcore_close (int);
|
||
+
|
||
+static void
|
||
+get_kcore_registers (int);
|
||
+
|
||
+static int
|
||
+xfer_mem (CORE_ADDR, char *, int, int, struct mem_attrib *,
|
||
+ struct target_ops *);
|
||
+
|
||
+static int
|
||
+xfer_umem (CORE_ADDR, char *, int, int);
|
||
+
|
||
+static char *core_file;
|
||
+static kvm_t *core_kd;
|
||
+static struct pcb cur_pcb;
|
||
+static struct kinfo_proc *cur_proc;
|
||
+
|
||
+static struct target_ops kcore_ops;
|
||
+
|
||
+int kernel_debugging;
|
||
+int kernel_writablecore;
|
||
+
|
||
+/* Read the "thing" at kernel address 'addr' into the space pointed to
|
||
+ by point. The length of the "thing" is determined by the type of p.
|
||
+ Result is non-zero if transfer fails. */
|
||
+
|
||
+#define kvread(addr, p) \
|
||
+ (target_read_memory ((CORE_ADDR) (addr), (char *) (p), sizeof (*(p))))
|
||
+
|
||
+static CORE_ADDR
|
||
+ksym_kernbase (void)
|
||
+{
|
||
+ static CORE_ADDR kernbase;
|
||
+ struct minimal_symbol *sym;
|
||
+
|
||
+ if (kernbase == 0)
|
||
+ {
|
||
+ sym = lookup_minimal_symbol ("kernbase", NULL, NULL);
|
||
+ if (sym == NULL) {
|
||
+ kernbase = KERNBASE;
|
||
+ } else {
|
||
+ kernbase = SYMBOL_VALUE_ADDRESS (sym);
|
||
+ }
|
||
+ }
|
||
+ return kernbase;
|
||
+}
|
||
+
|
||
+#define KERNOFF (ksym_kernbase ())
|
||
+#define INKERNEL(x) ((x) >= KERNOFF)
|
||
+
|
||
+CORE_ADDR
|
||
+ksym_lookup(const char *name)
|
||
+{
|
||
+ struct minimal_symbol *sym;
|
||
+
|
||
+ sym = lookup_minimal_symbol (name, NULL, NULL);
|
||
+ if (sym == NULL)
|
||
+ error ("kernel symbol `%s' not found.", name);
|
||
+
|
||
+ return SYMBOL_VALUE_ADDRESS (sym);
|
||
+}
|
||
+
|
||
+/* Provide the address of an initial PCB to use.
|
||
+ If this is a crash dump, try for "dumppcb".
|
||
+ If no "dumppcb" or it's /dev/mem, use proc0.
|
||
+ Return the core address of the PCB we found. */
|
||
+
|
||
+static CORE_ADDR
|
||
+initial_pcb (void)
|
||
+{
|
||
+ struct minimal_symbol *sym;
|
||
+ CORE_ADDR addr;
|
||
+ void *val;
|
||
+
|
||
+ /* Make sure things are open... */
|
||
+ if (!core_kd || !core_file)
|
||
+ return (0);
|
||
+
|
||
+ /* If this is NOT /dev/mem try for dumppcb. */
|
||
+ if (strncmp (core_file, _PATH_DEV, sizeof _PATH_DEV - 1))
|
||
+ {
|
||
+ sym = lookup_minimal_symbol ("dumppcb", NULL, NULL);
|
||
+ if (sym != NULL)
|
||
+ {
|
||
+ addr = SYMBOL_VALUE_ADDRESS (sym);
|
||
+ return (addr);
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* OK, just use thread0's pcb. Note that curproc might
|
||
+ not exist, and if it does, it will point to gdb.
|
||
+ Therefore, just use proc0 and let the user set
|
||
+ some other context if they care about it. */
|
||
+
|
||
+ addr = ksym_lookup ("thread0");
|
||
+ if (kvread (addr, &val))
|
||
+ {
|
||
+ error ("cannot read thread0 pointer at %x\n", addr);
|
||
+ val = 0;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Read the PCB address in thread structure. */
|
||
+ addr += offsetof (struct thread, td_pcb);
|
||
+ if (kvread (addr, &val))
|
||
+ {
|
||
+ error ("cannot read thread0->td_pcb pointer at %x\n", addr);
|
||
+ val = 0;
|
||
+ }
|
||
+ }
|
||
+
|
||
+ /* thread0 is wholly in the kernel and cur_proc is only used for
|
||
+ reading user mem, so no point in setting this up. */
|
||
+ cur_proc = 0;
|
||
+
|
||
+ return ((CORE_ADDR)val);
|
||
+}
|
||
+
|
||
+/* Set the current context to that of the PCB struct at the system address
|
||
+ passed. */
|
||
+
|
||
+static int
|
||
+set_context (CORE_ADDR addr)
|
||
+{
|
||
+ CORE_ADDR procaddr = 0;
|
||
+
|
||
+ if (kvread (addr, &cur_pcb))
|
||
+ error ("cannot read pcb at %#x", addr);
|
||
+
|
||
+ /* Fetch all registers from core file. */
|
||
+ target_fetch_registers (-1);
|
||
+
|
||
+ /* Now, set up the frame cache, and print the top of stack. */
|
||
+ flush_cached_frames ();
|
||
+ set_current_frame (create_new_frame (read_fp (), read_pc ()));
|
||
+ select_frame (get_current_frame ());
|
||
+ return (0);
|
||
+}
|
||
+
|
||
+/* Discard all vestiges of any previous core file and mark data and stack
|
||
+ spaces as empty. */
|
||
+
|
||
+/* ARGSUSED */
|
||
+static void
|
||
+kcore_close (int quitting)
|
||
+{
|
||
+
|
||
+ inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */
|
||
+
|
||
+ if (core_kd)
|
||
+ {
|
||
+ kvm_close (core_kd);
|
||
+ free (core_file);
|
||
+ core_file = NULL;
|
||
+ core_kd = NULL;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* This routine opens and sets up the core file bfd. */
|
||
+
|
||
+static void
|
||
+kcore_open (char *filename /* the core file */, int from_tty)
|
||
+{
|
||
+ kvm_t *kd;
|
||
+ const char *p;
|
||
+ struct cleanup *old_chain;
|
||
+ char buf[256], *cp;
|
||
+ int ontop;
|
||
+ CORE_ADDR addr;
|
||
+
|
||
+ target_preopen (from_tty);
|
||
+
|
||
+ /* The exec file is required for symbols. */
|
||
+ if (exec_bfd == NULL)
|
||
+ error ("No kernel exec file specified");
|
||
+
|
||
+ if (core_kd)
|
||
+ {
|
||
+ error ("No core file specified."
|
||
+ " (Use `detach' to stop debugging a core file.)");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ if (!filename)
|
||
+ {
|
||
+ error ("No core file specified.");
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ filename = tilde_expand (filename);
|
||
+ if (filename[0] != '/')
|
||
+ {
|
||
+ cp = concat (current_directory, "/", filename, NULL);
|
||
+ free (filename);
|
||
+ filename = cp;
|
||
+ }
|
||
+
|
||
+ old_chain = make_cleanup (free, filename);
|
||
+
|
||
+ kd = kvm_open (bfd_get_filename(exec_bfd), filename, NULL,
|
||
+ kernel_writablecore ? O_RDWR: O_RDONLY, 0);
|
||
+ if (kd == NULL)
|
||
+ {
|
||
+ perror_with_name (filename);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /* Looks semi-reasonable. Toss the old core file and work on the new. */
|
||
+
|
||
+ discard_cleanups (old_chain); /* Don't free filename any more. */
|
||
+ core_file = filename;
|
||
+ unpush_target (&kcore_ops);
|
||
+ ontop = !push_target (&kcore_ops);
|
||
+
|
||
+ /* Note unpush_target (above) calls kcore_close. */
|
||
+ core_kd = kd;
|
||
+
|
||
+ /* Print out the panic string if there is one. */
|
||
+ if (kvread (ksym_lookup ("panicstr"), &addr) == 0 &&
|
||
+ addr != 0 &&
|
||
+ target_read_memory (addr, buf, sizeof(buf)) == 0)
|
||
+ {
|
||
+
|
||
+ for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++)
|
||
+ if (!isascii (*cp) || (!isprint (*cp) && !isspace (*cp)))
|
||
+ *cp = '?';
|
||
+ *cp = '\0';
|
||
+ if (buf[0] != '\0')
|
||
+ printf_filtered ("panic: %s\n", buf);
|
||
+ }
|
||
+
|
||
+ /* Print all the panic messages if possible. */
|
||
+ if (symfile_objfile != NULL)
|
||
+ {
|
||
+ printf ("panic messages:\n---\n");
|
||
+ snprintf (buf, sizeof buf,
|
||
+ "/sbin/dmesg -N %s -M %s | \
|
||
+ /usr/bin/awk '/^(panic:|Fatal trap) / { printing = 1 } \
|
||
+ { if (printing) print $0 }'",
|
||
+ symfile_objfile->name, filename);
|
||
+ fflush (stdout);
|
||
+ system (buf);
|
||
+ printf ("---\n");
|
||
+ }
|
||
+
|
||
+ if (!ontop)
|
||
+ {
|
||
+ warning ("you won't be able to access this core file until you terminate\n"
|
||
+ "your %s; do ``info files''", target_longname);
|
||
+ return;
|
||
+ }
|
||
+
|
||
+ /* Now, set up process context, and print the top of stack. */
|
||
+ (void)set_context (initial_pcb());
|
||
+ print_stack_frame (selected_frame, frame_relative_level(selected_frame), 1);
|
||
+}
|
||
+
|
||
+static void
|
||
+kcore_detach (char *args, int from_tty)
|
||
+{
|
||
+ if (args)
|
||
+ error ("Too many arguments");
|
||
+ unpush_target (&kcore_ops);
|
||
+ reinit_frame_cache ();
|
||
+ if (from_tty)
|
||
+ printf_filtered ("No kernel core file now.\n");
|
||
+}
|
||
+
|
||
+#ifdef __alpha__
|
||
+
|
||
+#include "alpha/tm-alpha.h"
|
||
+#include "alpha-tdep.h"
|
||
+
|
||
+#ifndef S0_REGNUM
|
||
+#define S0_REGNUM (ALPHA_T7_REGNUM+1)
|
||
+#endif
|
||
+
|
||
+fetch_kcore_registers (struct pcb *pcbp)
|
||
+{
|
||
+
|
||
+ /* First clear out any garbage. */
|
||
+ memset (registers, '\0', REGISTER_BYTES);
|
||
+
|
||
+ /* SP */
|
||
+ *(long *) ®isters[REGISTER_BYTE (SP_REGNUM)] =
|
||
+ pcbp->pcb_hw.apcb_ksp;
|
||
+
|
||
+ /* S0 through S6 */
|
||
+ memcpy (®isters[REGISTER_BYTE (S0_REGNUM)],
|
||
+ &pcbp->pcb_context[0], 7 * sizeof (long));
|
||
+
|
||
+ /* PC */
|
||
+ *(long *) ®isters[REGISTER_BYTE (PC_REGNUM)] =
|
||
+ pcbp->pcb_context[7];
|
||
+
|
||
+ registers_fetched ();
|
||
+}
|
||
+
|
||
+
|
||
+CORE_ADDR
|
||
+fbsd_kern_frame_saved_pc (struct frame_info *fi)
|
||
+{
|
||
+ struct minimal_symbol *sym;
|
||
+ CORE_ADDR this_saved_pc;
|
||
+
|
||
+ this_saved_pc = FRAME_SAVED_PC(fi);
|
||
+
|
||
+ sym = lookup_minimal_symbol_by_pc (this_saved_pc);
|
||
+
|
||
+ if (sym != NULL &&
|
||
+ (strcmp (SYMBOL_NAME (sym), "XentArith") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "XentIF") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "XentInt") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "XentMM") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "XentSys") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "XentUna") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "XentRestart") == 0))
|
||
+ {
|
||
+ return (read_memory_integer (fi->frame + 32 * 8, 8));
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ return (this_saved_pc);
|
||
+ }
|
||
+}
|
||
+
|
||
+#endif /* __alpha__ */
|
||
+
|
||
+#ifdef __i386__
|
||
+
|
||
+static CORE_ADDR
|
||
+ksym_maxuseraddr (void)
|
||
+{
|
||
+ static CORE_ADDR maxuseraddr;
|
||
+ struct minimal_symbol *sym;
|
||
+
|
||
+ if (maxuseraddr == 0)
|
||
+ {
|
||
+ sym = lookup_minimal_symbol ("PTmap", NULL, NULL);
|
||
+ if (sym == NULL) {
|
||
+ maxuseraddr = VM_MAXUSER_ADDRESS;
|
||
+ } else {
|
||
+ maxuseraddr = SYMBOL_VALUE_ADDRESS (sym);
|
||
+ }
|
||
+ }
|
||
+ return maxuseraddr;
|
||
+}
|
||
+
|
||
+
|
||
+/* Symbol names of kernel entry points. Use special frames. */
|
||
+#define KSYM_TRAP "calltrap"
|
||
+#define KSYM_INTR "Xintr"
|
||
+#define KSYM_FASTINTR "Xfastintr"
|
||
+#define KSYM_OLDSYSCALL "Xlcall_syscall"
|
||
+#define KSYM_SYSCALL "Xint0x80_syscall"
|
||
+
|
||
+/* The following is FreeBSD-specific hackery to decode special frames
|
||
+ and elide the assembly-language stub. This could be made faster by
|
||
+ defining a frame_type field in the machine-dependent frame information,
|
||
+ but we don't think that's too important right now. */
|
||
+enum frametype { tf_normal, tf_trap, tf_interrupt, tf_syscall };
|
||
+
|
||
+CORE_ADDR
|
||
+fbsd_kern_frame_saved_pc (struct frame_info *fr)
|
||
+{
|
||
+ struct minimal_symbol *sym;
|
||
+ CORE_ADDR this_saved_pc;
|
||
+ enum frametype frametype;
|
||
+
|
||
+ this_saved_pc = read_memory_integer (fr->frame + 4, 4);
|
||
+ sym = lookup_minimal_symbol_by_pc (this_saved_pc);
|
||
+ frametype = tf_normal;
|
||
+ if (sym != NULL)
|
||
+ {
|
||
+ if (strcmp (SYMBOL_NAME (sym), KSYM_TRAP) == 0)
|
||
+ frametype = tf_trap;
|
||
+ else
|
||
+ if (strncmp (SYMBOL_NAME (sym), KSYM_INTR,
|
||
+ strlen (KSYM_INTR)) == 0 || strncmp (SYMBOL_NAME(sym),
|
||
+ KSYM_FASTINTR, strlen (KSYM_FASTINTR)) == 0)
|
||
+ frametype = tf_interrupt;
|
||
+ else
|
||
+ if (strcmp (SYMBOL_NAME (sym), KSYM_SYSCALL) == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), KSYM_OLDSYSCALL) == 0)
|
||
+ frametype = tf_syscall;
|
||
+ }
|
||
+
|
||
+ switch (frametype)
|
||
+ {
|
||
+ default:
|
||
+ case tf_normal:
|
||
+ return (this_saved_pc);
|
||
+#define oEIP offsetof (struct trapframe, tf_eip)
|
||
+
|
||
+ case tf_trap:
|
||
+ return (read_memory_integer (fr->frame + 8 + oEIP, 4));
|
||
+
|
||
+ case tf_interrupt:
|
||
+ return (read_memory_integer (fr->frame + 12 + oEIP, 4));
|
||
+
|
||
+ case tf_syscall:
|
||
+ return (read_memory_integer (fr->frame + 8 + oEIP, 4));
|
||
+#undef oEIP
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+fetch_kcore_registers (struct pcb *pcb)
|
||
+{
|
||
+ int i;
|
||
+ int noreg;
|
||
+
|
||
+ /* Get the register values out of the sys pcb and store them where
|
||
+ `read_register' will find them. */
|
||
+ /*
|
||
+ * XXX many registers aren't available.
|
||
+ * XXX for the non-core case, the registers are stale - they are for
|
||
+ * the last context switch to the debugger.
|
||
+ * XXX gcc's register numbers aren't all #defined in tm-i386.h.
|
||
+ */
|
||
+ noreg = 0;
|
||
+ for (i = 0; i < 3; ++i) /* eax,ecx,edx */
|
||
+ supply_register (i, (char *)&noreg);
|
||
+
|
||
+ supply_register (3, (char *) &pcb->pcb_ebx);
|
||
+ supply_register (SP_REGNUM, (char *) &pcb->pcb_esp);
|
||
+ supply_register (FP_REGNUM, (char *) &pcb->pcb_ebp);
|
||
+ supply_register (6, (char *) &pcb->pcb_esi);
|
||
+ supply_register (7, (char *) &pcb->pcb_edi);
|
||
+ supply_register (PC_REGNUM, (char *) &pcb->pcb_eip);
|
||
+
|
||
+ for (i = 9; i < 14; ++i) /* eflags, cs, ss, ds, es, fs */
|
||
+ supply_register (i, (char *) &noreg);
|
||
+ supply_register (15, (char *) &pcb->pcb_gs);
|
||
+
|
||
+ /* XXX 80387 registers? */
|
||
+}
|
||
+
|
||
+#endif /* __i386__ */
|
||
+
|
||
+#ifdef __sparc64__
|
||
+
|
||
+#define SPARC_INTREG_SIZE 8
|
||
+
|
||
+static void
|
||
+fetch_kcore_registers (struct pcb *pcbp)
|
||
+{
|
||
+ static struct frame top;
|
||
+ CORE_ADDR f_addr;
|
||
+ int i;
|
||
+
|
||
+ /* Get the register values out of the sys pcb and store them where
|
||
+ `read_register' will find them. */
|
||
+ /*
|
||
+ * XXX many registers aren't available.
|
||
+ * XXX for the non-core case, the registers are stale - they are for
|
||
+ * the last context switch to the debugger.
|
||
+ * XXX do something with the floating-point registers?
|
||
+ */
|
||
+ supply_register (SP_REGNUM, &pcbp->pcb_fp);
|
||
+ supply_register (PC_REGNUM, &pcbp->pcb_pc);
|
||
+ f_addr = extract_address (&pcbp->pcb_fp, SPARC_INTREG_SIZE);
|
||
+ /* Load the previous frame by hand (XXX) and supply it. */
|
||
+ read_memory (f_addr + SPOFF, (char *)&top, sizeof (top));
|
||
+ for (i = 0; i < 8; i++)
|
||
+ supply_register (i + L0_REGNUM, &top.fr_local[i]);
|
||
+ for (i = 0; i < 8; i++)
|
||
+ supply_register (i + I0_REGNUM, &top.fr_in[i]);
|
||
+}
|
||
+
|
||
+CORE_ADDR
|
||
+fbsd_kern_frame_saved_pc (struct frame_info *fi)
|
||
+{
|
||
+ struct minimal_symbol *sym;
|
||
+ CORE_ADDR frame, pc_addr, pc;
|
||
+ char *buf;
|
||
+
|
||
+ buf = alloca (MAX_REGISTER_RAW_SIZE);
|
||
+ /* XXX: duplicates fi->extra_info->bottom. */
|
||
+ frame = (fi->next != NULL) ? fi->next->frame : read_sp ();
|
||
+ pc_addr = frame + offsetof (struct frame, fr_in[7]);
|
||
+
|
||
+#define READ_PC(pc, a, b) do { \
|
||
+ read_memory (a, b, SPARC_INTREG_SIZE); \
|
||
+ pc = extract_address (b, SPARC_INTREG_SIZE); \
|
||
+} while (0)
|
||
+
|
||
+ READ_PC (pc, pc_addr, buf);
|
||
+
|
||
+ sym = lookup_minimal_symbol_by_pc (pc);
|
||
+ if (sym != NULL)
|
||
+ {
|
||
+ if (strncmp (SYMBOL_NAME (sym), "tl0_", 4) == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "btext") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "mp_startup") == 0 ||
|
||
+ strcmp (SYMBOL_NAME (sym), "fork_trampoline") == 0)
|
||
+ {
|
||
+ /*
|
||
+ * Ugly kluge: user space addresses aren't separated from kernel
|
||
+ * ones by range; if encountering a trap from user space, just
|
||
+ * return a 0 to stop the trace.
|
||
+ * Do the same for entry points of kernel processes to avoid
|
||
+ * printing garbage.
|
||
+ */
|
||
+ pc = 0;
|
||
+ }
|
||
+ if (strncmp (SYMBOL_NAME (sym), "tl1_", 4) == 0)
|
||
+ {
|
||
+ pc_addr = fi->frame + sizeof (struct frame) +
|
||
+ offsetof (struct trapframe, tf_tpc);
|
||
+ READ_PC (pc, pc_addr, buf);
|
||
+ }
|
||
+ }
|
||
+ return (pc);
|
||
+}
|
||
+
|
||
+#endif /* __sparc64__ */
|
||
+
|
||
+/* Get the registers out of a core file. This is the machine-
|
||
+ independent part. Fetch_core_registers is the machine-dependent
|
||
+ part, typically implemented in the xm-file for each architecture. */
|
||
+
|
||
+/* We just get all the registers, so we don't use regno. */
|
||
+
|
||
+/* ARGSUSED */
|
||
+static void
|
||
+get_kcore_registers (int regno)
|
||
+{
|
||
+
|
||
+ /* XXX - Only read the pcb when set_context() is called.
|
||
+ When looking at a live kernel this may be a problem,
|
||
+ but the user can do another "proc" or "pcb" command to
|
||
+ grab a new copy of the pcb... */
|
||
+
|
||
+ /* Zero out register set then fill in the ones we know about. */
|
||
+ fetch_kcore_registers (&cur_pcb);
|
||
+}
|
||
+
|
||
+static void
|
||
+kcore_files_info (t)
|
||
+ struct target_ops *t;
|
||
+{
|
||
+ printf_filtered ("\t`%s'\n", core_file);
|
||
+}
|
||
+
|
||
+/* If mourn is being called in all the right places, this could be say
|
||
+ `gdb internal error' (since generic_mourn calls breakpoint_init_inferior). */
|
||
+
|
||
+static int
|
||
+ignore (CORE_ADDR addr, char *contents)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+static int
|
||
+xfer_kmem (CORE_ADDR memaddr, char *myaddr, int len, int write,
|
||
+ struct mem_attrib *attrib, struct target_ops *target)
|
||
+{
|
||
+ int n;
|
||
+
|
||
+
|
||
+ if (!INKERNEL (memaddr))
|
||
+ return xfer_umem (memaddr, myaddr, len, write);
|
||
+
|
||
+ if (core_kd == NULL)
|
||
+ return 0;
|
||
+
|
||
+ if (write)
|
||
+ n = kvm_write (core_kd, memaddr, myaddr, len);
|
||
+ else
|
||
+ n = kvm_read (core_kd, memaddr, myaddr, len) ;
|
||
+ if (n < 0) {
|
||
+ fprintf_unfiltered (gdb_stderr, "can not access 0x%x, %s\n",
|
||
+ memaddr, kvm_geterr (core_kd));
|
||
+ n = 0;
|
||
+ }
|
||
+
|
||
+ return n;
|
||
+}
|
||
+
|
||
+
|
||
+static int
|
||
+xfer_umem (CORE_ADDR memaddr, char *myaddr, int len, int write /* ignored */)
|
||
+{
|
||
+ int n = 0;
|
||
+
|
||
+ if (cur_proc == 0)
|
||
+ {
|
||
+ error ("---Can't read userspace from dump, or kernel process---\n");
|
||
+ return 0;
|
||
+ }
|
||
+
|
||
+ if (write)
|
||
+ error ("kvm_uwrite unimplemented\n");
|
||
+ else
|
||
+ n = kvm_uread (core_kd, cur_proc, memaddr, myaddr, len) ;
|
||
+
|
||
+ if (n < 0)
|
||
+ return 0;
|
||
+
|
||
+ return n;
|
||
+}
|
||
+
|
||
+static void
|
||
+set_proc_cmd (char *arg, int from_tty)
|
||
+{
|
||
+ CORE_ADDR addr, pid_addr, first_td;
|
||
+ void *val;
|
||
+ struct kinfo_proc *kp;
|
||
+ int cnt;
|
||
+ pid_t pid;
|
||
+
|
||
+ if (!arg)
|
||
+ error_no_arg ("proc address for the new context");
|
||
+
|
||
+ if (core_kd == NULL)
|
||
+ error ("no kernel core file");
|
||
+
|
||
+ addr = (CORE_ADDR) parse_and_eval_address (arg);
|
||
+
|
||
+ if (!INKERNEL (addr))
|
||
+ {
|
||
+ kp = kvm_getprocs (core_kd, KERN_PROC_PID, addr, &cnt);
|
||
+ if (!cnt)
|
||
+ error ("invalid pid");
|
||
+ addr = (CORE_ADDR)kp->ki_paddr;
|
||
+ cur_proc = kp;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* Update cur_proc. */
|
||
+ pid_addr = addr + offsetof (struct proc, p_pid);
|
||
+ if (kvread (pid_addr, &pid))
|
||
+ error ("cannot read pid ptr");
|
||
+ cur_proc = kvm_getprocs (core_kd, KERN_PROC_PID, pid, &cnt);
|
||
+ if (!cnt)
|
||
+ error("invalid pid");
|
||
+ }
|
||
+
|
||
+ /* Find the first thread in the process. XXXKSE */
|
||
+ addr += offsetof (struct proc, p_threads.tqh_first);
|
||
+ if (kvread (addr, &first_td))
|
||
+ error ("cannot read thread ptr");
|
||
+
|
||
+ /* Read the PCB address in thread structure. */
|
||
+ addr = first_td + offsetof (struct thread, td_pcb);
|
||
+ if (kvread (addr, &val))
|
||
+ error("cannot read pcb ptr");
|
||
+
|
||
+ /* Read the PCB address in proc structure. */
|
||
+ if (set_context ((CORE_ADDR) val))
|
||
+ error ("invalid proc address");
|
||
+}
|
||
+#else
|
||
+int kernel_debugging = 0;
|
||
+int kernel_writablecore = 0;
|
||
+
|
||
+CORE_ADDR
|
||
+fbsd_kern_frame_saved_pc (struct frame_info *fi)
|
||
+{
|
||
+ return 0;
|
||
+}
|
||
+#endif
|
||
+
|
||
+void
|
||
+_initialize_kcorelow (void)
|
||
+{
|
||
+#if __FreeBSD_version >= 500032
|
||
+ kcore_ops.to_shortname = "kcore";
|
||
+ kcore_ops.to_longname = "Kernel core dump file";
|
||
+ kcore_ops.to_doc =
|
||
+ "Use a core file as a target. Specify the filename of the core file.";
|
||
+ kcore_ops.to_open = kcore_open;
|
||
+ kcore_ops.to_close = kcore_close;
|
||
+ kcore_ops.to_attach = find_default_attach;
|
||
+ kcore_ops.to_detach = kcore_detach;
|
||
+ kcore_ops.to_fetch_registers = get_kcore_registers;
|
||
+ kcore_ops.to_xfer_memory = xfer_kmem;
|
||
+ kcore_ops.to_files_info = kcore_files_info;
|
||
+ kcore_ops.to_create_inferior = find_default_create_inferior;
|
||
+ kcore_ops.to_stratum = kcore_stratum;
|
||
+ kcore_ops.to_has_memory = 1;
|
||
+ kcore_ops.to_has_stack = 1;
|
||
+ kcore_ops.to_has_registers = 1;
|
||
+ kcore_ops.to_magic = OPS_MAGIC;
|
||
+
|
||
+ add_target (&kcore_ops);
|
||
+ add_com ("proc", class_obscure, set_proc_cmd, "Set current process context");
|
||
+#endif
|
||
+}
|