diff options
Diffstat (limited to 'gnu/usr.bin/binutils/gdb')
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/Makefile | 82 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/config.h | 91 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/gdb.1 | 390 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c | 802 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/i386/kvm-fbsd.c | 941 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/i386/nm.h | 146 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/i386/tm.h | 66 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/i386/version.c | 2 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/i386/xm.h | 8 | ||||
| -rw-r--r-- | gnu/usr.bin/binutils/gdb/kvm-fbsd.c | 941 |
10 files changed, 2112 insertions, 1357 deletions
diff --git a/gnu/usr.bin/binutils/gdb/Makefile b/gnu/usr.bin/binutils/gdb/Makefile index 47ad0db365e5..981ac453c372 100644 --- a/gnu/usr.bin/binutils/gdb/Makefile +++ b/gnu/usr.bin/binutils/gdb/Makefile @@ -1,16 +1,20 @@ # $FreeBSD$ PROG = gdb + +GDBDIR= ${.CURDIR}/../../../../contrib/gdb +.PATH: ${GDBDIR}/gdb +.PATH: ${GDBDIR}/opcodes + BINDIR= /usr/bin -CLEANFILES+= y.tab.h c-exp.tab.c ch-exp.tab.c m2-exp.tab.c SRCS = annotate.c blockframe.c breakpoint.c buildsym.c c-lang.c \ c-typeprint.c c-valprint.c ch-lang.c ch-typeprint.c \ - ch-valprint.c coffread.c command.c complaints.c copying.c core.c \ - coredep.c corelow.c cp-valprint.c \ - dcache.c dbxread.c demangle.c disassemble.c dis-buf.c dwarfread.c \ + ch-valprint.c coffread.c command.c complaints.c copying.c core-aout.c \ + corelow.c cp-valprint.c \ + dcache.c dbxread.c demangle.c dwarfread.c \ elfread.c environ.c eval.c exec.c expprint.c \ - findvar.c fork-child.c freebsd-nat.c gdbtypes.c i386-dis.c \ - i386-pinsn.c i386-tdep.c infcmd.c inflow.c infptrace.c \ + findvar.c fork-child.c i386b-nat.c gdbtypes.c \ + i386-tdep.c infcmd.c inflow.c infptrace.c \ infrun.c inftarg.c init.c kcorelow.c language.c \ m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \ mem-break.c minsyms.c objfiles.c parse.c \ @@ -19,36 +23,29 @@ SRCS = annotate.c blockframe.c breakpoint.c buildsym.c c-lang.c \ symtab.c target.c thread.c top.c \ typeprint.c utils.c valarith.c valops.c \ valprint.c values.c version.c serial.c ser-unix.c mdebugread.c\ - c-exp.tab.c ch-exp.tab.c m2-exp.tab.c compat_que.c - -c-exp.tab.c: $(.CURDIR)/c-exp.y - yacc -d -p c_ $(.CURDIR)/c-exp.y - sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \ - -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \ - -e 's/realloc/xrealloc/g' < y.tab.c > c-exp.new - rm -f y.tab.c - mv -f c-exp.new ./c-exp.tab.c + c-exp.tab.c f-exp.tab.c m2-exp.tab.c i387-tdep.c \ + kvm-fbsd.c bcache.c \ + corefile.c ch-exp.c f-lang.c scm-exp.c scm-lang.c \ + scm-valprint.c f-typeprint.c f-valprint.c nlmread.c \ + callback.c +SRCS+= i386-dis.c dis-buf.c disassemble.c -ch-exp.tab.c: $(.CURDIR)/ch-exp.y - yacc -d -p ch_ $(.CURDIR)/ch-exp.y - sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \ - -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \ - -e 's/realloc/xrealloc/g' < y.tab.c > ch-exp.new - rm -f y.tab.c - mv -f ch-exp.new ./ch-exp.tab.c - -m2-exp.tab.c: $(.CURDIR)/m2-exp.y - yacc -d -p m2_ $(.CURDIR)/m2-exp.y - sed -e '/extern.*malloc/d' -e '/extern.*realloc/d' -e '/extern.*free/d' \ - -e '/include.*malloc.h/d' -e 's/malloc/xmalloc/g' \ - -e 's/realloc/xrealloc/g' < y.tab.c > m2-exp.new - rm -f y.tab.c - mv -f m2-exp.new ./m2-exp.tab.c +CFLAGS+= -I$(.CURDIR) -I${DESTDIR}/usr/include/readline -I$(.CURDIR)/../bfd +# use phkmalloc +CFLAGS+= -DNO_MMALLOC +# uncomment the next line if you want to debug gdb +#CFLAGS+= -g +.if exists(${.OBJDIR}/../bfd) +LDADD+= -L${.OBJDIR}/../bfd -lbfd +DPADD+= ${.OBJDIR}/../bfd/libbfd.a +.else +LDADD+= -L${.CURDIR}/../bfd/ -lbfd +DPADD+= ${.CURDIR}/../bfd/libbfd.a +.endif -CFLAGS+= -I$(.CURDIR)/. -I${DESTDIR}/usr/include/readline -I$(.CURDIR)/../bfd -DPADD+= ${LIBREADLINE} ${LIBTERMCAP} ${LIBGNUREGEX} -LDADD+= -lreadline -ltermcap -lgnuregex +DPADD+= ${LIBREADLINE} ${LIBGNUREGEX} +LDADD+= -lreadline -lgnuregex .if exists(${.OBJDIR}/../libiberty) LDADD+= -L${.OBJDIR}/../libiberty -liberty @@ -58,20 +55,15 @@ LDADD+= -L${.CURDIR}/../libiberty/ -liberty DPADD+= ${.CURDIR}/../libiberty/libiberty.a .endif -.if exists(${.OBJDIR}/../bfd) -LDADD+= -L${.OBJDIR}/../bfd -lbfd -DPADD+= ${.OBJDIR}/../bfd/libbfd.a -.else -LDADD+= -L${.CURDIR}/../bfd/ -lbfd -DPADD+= ${.CURDIR}/../bfd/libbfd.a -.endif +DPADD+= ${LIBTERMCAP} +LDADD+= -ltermcap -lmalloc -.if exists(${.OBJDIR}/../mmalloc) -LDADD+= -L${.OBJDIR}/../mmalloc -lmmalloc -DPADD+= ${.OBJDIR}/../mmalloc/libmmalloc.a +.if exists(${.OBJDIR}/../libiberty) +LDADD+= -L${.OBJDIR}/../libiberty -liberty +DPADD+= ${.OBJDIR}/../libiberty/libiberty.a .else -LDADD+= -L${.CURDIR}/../mmalloc/ -lmmalloc -DPADD+= ${.CURDIR}/../mmalloc/libmmalloc.a +LDADD+= -L${.CURDIR}/../libiberty/ -liberty +DPADD+= ${.CURDIR}/../libiberty/libiberty.a .endif .include <bsd.prog.mk> diff --git a/gnu/usr.bin/binutils/gdb/config.h b/gnu/usr.bin/binutils/gdb/config.h new file mode 100644 index 000000000000..29f0a3c0e18a --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/config.h @@ -0,0 +1,91 @@ +/* config.h. Generated automatically by configure. */ +/* config.in. Generated automatically from configure.in by autoheader. */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* #undef _ALL_SOURCE */ +#endif + +/* Define if the `long double' type works. */ +#define HAVE_LONG_DOUBLE 1 + +/* Define if you have a working `mmap' system call. */ +#define HAVE_MMAP 1 + +/* Define if on MINIX. */ +/* #undef _MINIX */ + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define if you need to in order for stat and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if fpregset_t type is available. */ +/* #undef HAVE_FPREGSET_T */ + +/* Define if gregset_t type is available. */ +/* #undef HAVE_GREGSET_T */ + +/* Define if the "%Lg" format works to print long doubles. */ +#define PRINTF_HAS_LONG_DOUBLE 1 + +/* Define if you have the getpagesize function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define if you have the sbrk function. */ +#define HAVE_SBRK 1 + +/* Define if you have the setpgid function. */ +#define HAVE_SETPGID 1 + +/* Define if you have the valloc function. */ +#define HAVE_VALLOC 1 + +/* Define if you have the <endian.h> header file. */ +/* #undef HAVE_ENDIAN_H */ + +/* Define if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the <link.h> header file. */ +#define HAVE_LINK_H 1 + +/* Define if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the <sgtty.h> header file. */ +#define HAVE_SGTTY_H 1 + +/* Define if you have the <stddef.h> header file. */ +#define HAVE_STDDEF_H 1 + +/* Define if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the <strings.h> header file. */ +#define HAVE_STRINGS_H 1 + +/* Define if you have the <sys/procfs.h> header file. */ +/* #undef HAVE_SYS_PROCFS_H */ + +/* Define if you have the <termio.h> header file. */ +/* #undef HAVE_TERMIO_H */ + +/* Define if you have the <termios.h> header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the dl library (-ldl). */ +/* #undef HAVE_LIBDL */ diff --git a/gnu/usr.bin/binutils/gdb/gdb.1 b/gnu/usr.bin/binutils/gdb/gdb.1 deleted file mode 100644 index 13a6a771f25a..000000000000 --- a/gnu/usr.bin/binutils/gdb/gdb.1 +++ /dev/null @@ -1,390 +0,0 @@ -.\" Copyright (c) 1991 Free Software Foundation -.\" See section COPYING for conditions for redistribution -.\" $FreeBSD$ -.TH gdb 1 "4nov1991" "GNU Tools" "GNU Tools" -.SH NAME -gdb \- The GNU Debugger -.SH SYNOPSIS -.na -.TP -.B gdb -.RB "[\|" \-help "\|]" -.RB "[\|" \-nx "\|]" -.RB "[\|" \-q "\|]" -.RB "[\|" \-k "\|]" -.RB "[\|" \-w "\|]" -.RB "[\|" \-batch "\|]" -.RB "[\|" \-cd=\c -.I dir\c -\|] -.RB "[\|" \-f "\|]" -.RB "[\|" "\-b\ "\c -.IR bps "\|]" -.RB "[\|" "\-tty="\c -.IR dev "\|]" -.RB "[\|" "\-s "\c -.I symfile\c -\&\|] -.RB "[\|" "\-e "\c -.I prog\c -\&\|] -.RB "[\|" "\-se "\c -.I prog\c -\&\|] -.RB "[\|" "\-c "\c -.I core\c -\&\|] -.RB "[\|" "\-x "\c -.I cmds\c -\&\|] -.RB "[\|" "\-d "\c -.I dir\c -\&\|] -.RB "[\|" \c -.I prog\c -.RB "[\|" \c -.IR core \||\| procID\c -\&\|]\&\|] -.ad b -.SH DESCRIPTION -The purpose of a debugger such as GDB is to allow you to see what is -going on ``inside'' another program while it executes\(em\&or what another -program was doing at the moment it crashed. - -GDB can do four main kinds of things (plus other things in support of -these) to help you catch bugs in the act: - -.TP -\ \ \ \(bu -Start your program, specifying anything that might affect its behavior. - -.TP -\ \ \ \(bu -Make your program stop on specified conditions. - -.TP -\ \ \ \(bu -Examine what has happened, when your program has stopped. - -.TP -\ \ \ \(bu -Change things in your program, so you can experiment with correcting the -effects of one bug and go on to learn about another. -.PP - -You can use GDB to debug programs written in C, C++, and Modula-2. -Fortran support will be added when a GNU Fortran compiler is ready. - -GDB is invoked with the shell command \c -.B gdb\c -\&. Once started, it reads -commands from the terminal until you tell it to exit with the GDB -command \c -.B quit\c -\&. You can get online help from \c -.B gdb\c -\& itself -by using the command \c -.B help\c -\&. - -You can run \c -.B gdb\c -\& with no arguments or options; but the most -usual way to start GDB is with one argument or two, specifying an -executable program as the argument: -.sp -.br -gdb\ program -.br -.sp - -You can also start with both an executable program and a core file specified: -.sp -.br -gdb\ program\ core -.br -.sp - -You can, instead, specify a process ID as a second argument, if you want -to debug a running process: -.sp -.br -gdb\ program\ 1234 -.br -.sp - -would attach GDB to process \c -.B 1234\c -\& (unless you also have a file -named `\|\c -.B 1234\c -\&\|'; GDB does check for a core file first). - -Here are some of the most frequently needed GDB commands: -.TP -.B break \fR[\|\fIfile\fB:\fR\|]\fIfunction -\& -Set a breakpoint at \c -.I function\c -\& (in \c -.I file\c -\&). -.TP -.B run \fR[\|\fIarglist\fR\|] -Start your program (with \c -.I arglist\c -\&, if specified). -.TP -.B bt -Backtrace: display the program stack. -.TP -.BI print " expr"\c -\& -Display the value of an expression. -.TP -.B c -Continue running your program (after stopping, e.g. at a breakpoint). -.TP -.B next -Execute next program line (after stopping); step \c -.I over\c -\& any -function calls in the line. -.TP -.B step -Execute next program line (after stopping); step \c -.I into\c -\& any -function calls in the line. -.TP -.B help \fR[\|\fIname\fR\|] -Show information about GDB command \c -.I name\c -\&, or general information -about using GDB. -.TP -.B quit -Exit from GDB. -.PP -For full details on GDB, see \c -.I -Using GDB: A Guide to the GNU Source-Level Debugger\c -\&, by Richard M. Stallman and Roland H. Pesch. The same text is available online -as the \c -.B gdb\c -\& entry in the \c -.B info\c -\& program. -.SH OPTIONS -Any arguments other than options specify an executable -file and core file (or process ID); that is, the first argument -encountered with no -associated option flag is equivalent to a `\|\c -.B \-se\c -\&\|' option, and the -second, if any, is equivalent to a `\|\c -.B \-c\c -\&\|' option if it's the name of a file. Many options have -both long and short forms; both are shown here. The long forms are also -recognized if you truncate them, so long as enough of the option is -present to be unambiguous. (If you prefer, you can flag option -arguments with `\|\c -.B +\c -\&\|' rather than `\|\c -.B \-\c -\&\|', though we illustrate the -more usual convention.) - -All the options and command line arguments you give are processed -in sequential order. The order makes a difference when the -`\|\c -.B \-x\c -\&\|' option is used. - -.TP -.B \-help -.TP -.B \-h -List all options, with brief explanations. - -.TP -.BI "\-symbols=" "file"\c -.TP -.BI "\-s " "file"\c -\& -Read symbol table from file \c -.I file\c -\&. - -.TP -.BI "\-exec=" "file"\c -.TP -.BI "\-e " "file"\c -\& -Use file \c -.I file\c -\& as the executable file to execute when -appropriate, and for examining pure data in conjunction with a core -dump. - -.TP -.BI "\-se=" "file"\c -\& -Read symbol table from file \c -.I file\c -\& and use it as the executable -file. - -.TP -.BI "\-core=" "file"\c -.TP -.BI "\-c " "file"\c -\& -Use file \c -.I file\c -\& as a core dump to examine. - -.TP -.BI "\-command=" "file"\c -.TP -.BI "\-x " "file"\c -\& -Execute GDB commands from file \c -.I file\c -\&. - -.TP -.BI "\-directory=" "directory"\c -.TP -.BI "\-d " "directory"\c -\& -Add \c -.I directory\c -\& to the path to search for source files. -.PP - -.TP -.B \-nx -.TP -.B \-n -Do not execute commands from any `\|\c -.B .gdbinit\c -\&\|' initialization files. -Normally, the commands in these files are executed after all the -command options and arguments have been processed. - - -.TP -.B \-quiet -.TP -.B \-q -``Quiet''. Do not print the introductory and copyright messages. These -messages are also suppressed in batch mode. - -.TP -.B \-kernel -.TP -.B \-k -Puts GDB into kernel debugging mode. If no executable file is specified then -/kernel is used. If no core file is specified then /dev/mem is -used. Crash dumps can be examined by specifying both an executable and -a core file. - -.TP -.B \-wcore -.TP -.B \-w -This flag is only effective when debugging a "live" kernel. It makes the -core file (/dev/mem) writable so that kernel variables can be changed -during a debugging session. Use this with caution ! - -.TP -.B \-batch -Run in batch mode. Exit with status \c -.B 0\c -\& after processing all the command -files specified with `\|\c -.B \-x\c -\&\|' (and `\|\c -.B .gdbinit\c -\&\|', if not inhibited). -Exit with nonzero status if an error occurs in executing the GDB -commands in the command files. - -Batch mode may be useful for running GDB as a filter, for example to -download and run a program on another computer; in order to make this -more useful, the message -.sp -.br -Program\ exited\ normally. -.br -.sp - -(which is ordinarily issued whenever a program running under GDB control -terminates) is not issued when running in batch mode. - -.TP -.BI "\-cd=" "directory"\c -\& -Run GDB using \c -.I directory\c -\& as its working directory, -instead of the current directory. - -.TP -.B \-fullname -.TP -.B \-f -Emacs sets this option when it runs GDB as a subprocess. It tells GDB -to output the full file name and line number in a standard, -recognizable fashion each time a stack frame is displayed (which -includes each time the program stops). This recognizable format looks -like two `\|\c -.B \032\c -\&\|' characters, followed by the file name, line number -and character position separated by colons, and a newline. The -Emacs-to-GDB interface program uses the two `\|\c -.B \032\c -\&\|' characters as -a signal to display the source code for the frame. - -.TP -.BI "\-b " "bps"\c -\& -Set the line speed (baud rate or bits per second) of any serial -interface used by GDB for remote debugging. - -.TP -.BI "\-tty=" "device"\c -\& -Run using \c -.I device\c -\& for your program's standard input and output. -.PP - -.SH "SEE ALSO" -.RB "`\|" gdb "\|'" -entry in -.B info\c -\&; -.I -Using GDB: A Guide to the GNU Source-Level Debugger\c -, Richard M. Stallman and Roland H. Pesch, July 1991. -.SH COPYING -Copyright (c) 1991 Free Software Foundation, Inc. -.PP -Permission is granted to make and distribute verbatim copies of -this manual provided the copyright notice and this permission notice -are preserved on all copies. -.PP -Permission is granted to copy and distribute modified versions of this -manual under the conditions for verbatim copying, provided that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. -.PP -Permission is granted to copy and distribute translations of this -manual into another language, under the above conditions for modified -versions, except that this permission notice may be included in -translations approved by the Free Software Foundation instead of in -the original English. diff --git a/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c b/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c deleted file mode 100644 index 323f7511e065..000000000000 --- a/gnu/usr.bin/binutils/gdb/i386/freebsd-nat.c +++ /dev/null @@ -1,802 +0,0 @@ -/* Native-dependent code for BSD Unix running on i386's, for GDB. - Copyright 1988, 1989, 1991, 1992 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - $FreeBSD$ -*/ - -#include <sys/types.h> -#include <sys/param.h> -#include <signal.h> -#include <sys/user.h> -#include <machine/reg.h> -#include <machine/frame.h> -#include <sys/ptrace.h> - -#include "defs.h" -#include "symtab.h" - -/* this table must line up with REGISTER_NAMES in tm-i386v.h */ -/* symbols like 'tEAX' come from <machine/reg.h> */ -static int tregmap[] = -{ - tEAX, tECX, tEDX, tEBX, - tESP, tEBP, tESI, tEDI, - tEIP, tEFLAGS, tCS, tSS, - tDS, tES, tSS, tSS, /* lies: no fs or gs */ -}; - -/* blockend is the value of u.u_ar0, and points to the - place where ES is stored. */ - -int -i386_register_u_addr (blockend, regnum) - int blockend; - int regnum; -{ - return (blockend + 4 * tregmap[regnum]); -} - - -#define fpstate save87 -#define U_FPSTATE(u) u.u_pcb.pcb_savefpu - -static void -i387_to_double (from, to) - char *from; - char *to; -{ - long *lp; - /* push extended mode on 387 stack, then pop in double mode - * - * first, set exception masks so no error is generated - - * number will be rounded to inf or 0, if necessary - */ - asm ("pushl %eax"); /* grab a stack slot */ - asm ("fstcw (%esp)"); /* get 387 control word */ - asm ("movl (%esp),%eax"); /* save old value */ - asm ("orl $0x3f,%eax"); /* mask all exceptions */ - asm ("pushl %eax"); - asm ("fldcw (%esp)"); /* load new value into 387 */ - - asm ("movl 8(%ebp),%eax"); - asm ("fldt (%eax)"); /* push extended number on 387 stack */ - asm ("fwait"); - asm ("movl 12(%ebp),%eax"); - asm ("fstpl (%eax)"); /* pop double */ - asm ("fwait"); - - asm ("popl %eax"); /* flush modified control word */ - asm ("fnclex"); /* clear exceptions */ - asm ("fldcw (%esp)"); /* restore original control word */ - asm ("popl %eax"); /* flush saved copy */ -} - -#if 0 -static void -double_to_i387 (from, to) - char *from; - char *to; -{ - /* push double mode on 387 stack, then pop in extended mode - * no errors are possible because every 64-bit pattern - * can be converted to an extended - */ - asm ("movl 8(%ebp),%eax"); - asm ("fldl (%eax)"); - asm ("fwait"); - asm ("movl 12(%ebp),%eax"); - asm ("fstpt (%eax)"); - asm ("fwait"); -} -#endif - -struct env387 -{ - unsigned short control; - unsigned short r0; - unsigned short status; - unsigned short r1; - unsigned short tag; - unsigned short r2; - unsigned long eip; - unsigned short code_seg; - unsigned short opcode; - unsigned long operand; - unsigned short operand_seg; - unsigned short r3; - unsigned char regs[8][10]; -}; - -/* static */ void -print_387_control_word (control) -unsigned int control; -{ - printf ("control 0x%04x: ", control); - printf ("compute to "); - switch ((control >> 8) & 3) - { - case 0: printf ("24 bits; "); break; - case 1: printf ("(bad); "); break; - case 2: printf ("53 bits; "); break; - case 3: printf ("64 bits; "); break; - } - printf ("round "); - switch ((control >> 10) & 3) - { - case 0: printf ("NEAREST; "); break; - case 1: printf ("DOWN; "); break; - case 2: printf ("UP; "); break; - case 3: printf ("CHOP; "); break; - } - if (control & 0x3f) - { - printf ("mask:"); - if (control & 0x0001) printf (" INVALID"); - if (control & 0x0002) printf (" DENORM"); - if (control & 0x0004) printf (" DIVZ"); - if (control & 0x0008) printf (" OVERF"); - if (control & 0x0010) printf (" UNDERF"); - if (control & 0x0020) printf (" LOS"); - printf (";"); - } - printf ("\n"); - if (control & 0xe080) printf ("warning: reserved bits on 0x%x\n", - control & 0xe080); -} - -/* static */ void -print_387_status_word (status) - unsigned int status; -{ - printf ("status 0x%04x: ", status); - if (status & 0xff) - { - printf ("exceptions:"); - if (status & 0x0001) printf (" INVALID"); - if (status & 0x0002) printf (" DENORM"); - if (status & 0x0004) printf (" DIVZ"); - if (status & 0x0008) printf (" OVERF"); - if (status & 0x0010) printf (" UNDERF"); - if (status & 0x0020) printf (" LOS"); - if (status & 0x0040) printf (" FPSTACK"); - printf ("; "); - } - printf ("flags: %d%d%d%d; ", - (status & 0x4000) != 0, - (status & 0x0400) != 0, - (status & 0x0200) != 0, - (status & 0x0100) != 0); - - printf ("top %d\n", (status >> 11) & 7); -} - -static void -print_387_status (status, ep) - unsigned short status; - struct env387 *ep; -{ - int i; - int bothstatus; - int top; - int fpreg; - unsigned char *p; - - bothstatus = ((status != 0) && (ep->status != 0)); - if (status != 0) - { - if (bothstatus) - printf ("u: "); - print_387_status_word ((unsigned int)status); - } - - if (ep->status != 0) - { - if (bothstatus) - printf ("e: "); - print_387_status_word ((unsigned int)ep->status); - } - - print_387_control_word ((unsigned int)ep->control); - printf ("opcode 0x%x; ", ep->opcode); - printf ("pc 0x%x:0x%x; ", ep->code_seg, ep->eip); - printf ("operand 0x%x:0x%x\n", ep->operand_seg, ep->operand); - - top = (ep->status >> 11) & 7; - - printf (" regno tag msb lsb value\n"); - for (fpreg = 7; fpreg >= 0; fpreg--) - { - int st_regno; - double val; - - /* The physical regno `fpreg' is only relevant as an index into the - * tag word. Logical `%st' numbers are required for indexing ep->regs. - */ - st_regno = (fpreg + 8 - top) & 7; - - printf ("%%st(%d) %s ", st_regno, fpreg == top ? "=>" : " "); - - switch ((ep->tag >> (fpreg * 2)) & 3) - { - case 0: printf ("valid "); break; - case 1: printf ("zero "); break; - case 2: printf ("trap "); break; - case 3: printf ("empty "); break; - } - for (i = 9; i >= 0; i--) - printf ("%02x", ep->regs[st_regno][i]); - - i387_to_double (ep->regs[st_regno], (char *)&val); - printf (" %g\n", val); - } -} - -void -i386_float_info () -{ - struct user u; /* just for address computations */ - int i; - /* fpstate defined in <sys/user.h> */ - struct fpstate *fpstatep; - char buf[sizeof (struct fpstate) + 2 * sizeof (int)]; - unsigned int uaddr; - char fpvalid; - unsigned int rounded_addr; - unsigned int rounded_size; - /*extern int corechan;*/ - int skip; - extern int inferior_pid; - - uaddr = (char *)&U_FPSTATE(u) - (char *)&u; - if (inferior_pid) - { - int *ip; - - rounded_addr = uaddr & -sizeof (int); - rounded_size = (((uaddr + sizeof (struct fpstate)) - uaddr) + - sizeof (int) - 1) / sizeof (int); - skip = uaddr - rounded_addr; - - ip = (int *)buf; - for (i = 0; i < rounded_size; i++) - { - *ip++ = ptrace (PT_READ_U, inferior_pid, (caddr_t)rounded_addr, 0); - rounded_addr += sizeof (int); - } - } - else - { -#if 1 - printf("float info: can't do a core file (yet)\n"); - return; -#else - if (lseek (corechan, uaddr, 0) < 0) - perror_with_name ("seek on core file"); - if (myread (corechan, buf, sizeof (struct fpstate)) < 0) - perror_with_name ("read from core file"); - skip = 0; -#endif - } - - fpstatep = (struct fpstate *)(buf + skip); - print_387_status (fpstatep->sv_ex_sw, (struct env387 *)fpstatep); -} - -#ifdef SETUP_ARBITRARY_FRAME -FRAME -setup_arbitrary_frame (numargs, args) -int numargs; -unsigned int *args; -{ - if (numargs > 2) - error ("Too many args in frame specification"); - return create_new_frame ((CORE_ADDR)args[0], (CORE_ADDR)args[1]); -} -#endif - -#ifdef KERNEL_DEBUG -#include <sys/proc.h> -#include <sys/stat.h> -#include <sys/fcntl.h> -#include <sys/sysctl.h> -#include <unistd.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> - -#include <machine/vmparam.h> -#include <machine/pcb.h> -#include <machine/frame.h> - -#define KERNOFF ((unsigned)KERNBASE) -#define INKERNEL(x) ((x) >= KERNOFF) - -static CORE_ADDR sbr; -static CORE_ADDR curpcb; -static CORE_ADDR kstack; -static int found_pcb; -static int devmem; -static int kfd; -static struct pcb pcb; -int read_pcb (int, CORE_ADDR); -static CORE_ADDR kvtophys (int, CORE_ADDR); -static physrd(int, u_int, char*, int); - -extern CORE_ADDR ksym_lookup(const char *); - -/* substitutes for the stuff in libkvm which doesn't work */ -/* most of this was taken from the old kgdb */ - -/* we don't need all this stuff, but the call should look the same */ -kvm_open (efile, cfile, sfile, perm, errout) -char *efile; -char *cfile; -char *sfile; /* makes this kvm_open more compatible to the one in libkvm */ -int perm; -char *errout; /* makes this kvm_open more compatible to the one in libkvm */ -{ - struct stat stb; - CORE_ADDR addr; - int cfd; - - if ((cfd = open(cfile, perm, 0)) < 0) - return (cfd); - - fstat(cfd, &stb); - if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) { - devmem = 1; - kfd = open ("/dev/kmem", perm, 0); - } - - physrd(cfd, ksym_lookup("IdlePTD") - KERNOFF, (char*)&sbr, sizeof sbr); - printf("IdlePTD %x\n", sbr); - curpcb = ksym_lookup("curpcb") - KERNOFF; - physrd(cfd, curpcb, (char*)&curpcb, sizeof curpcb); - kstack = ksym_lookup("kstack"); - - found_pcb = 1; /* for vtophys */ - if (!devmem) - read_pcb(cfd, ksym_lookup("dumppcb") - KERNOFF); - else - read_pcb(cfd, kvtophys(cfd, kstack)); - - return (cfd); -} - -kvm_close (fd) -{ - return (close (fd)); -} - -kvm_write(core_kd, memaddr, myaddr, len) -CORE_ADDR memaddr; -char *myaddr; -{ - int cc; - - if (devmem) { - if (kfd > 0) { - /* - * Just like kvm_read, only we write. - */ - errno = 0; - if (lseek(kfd, (off_t)memaddr, 0) < 0 && errno != 0) { - error("kvm_write:invalid address (%x)", memaddr); - return (0); - } - cc = write(kfd, myaddr, len); - if (cc < 0) { - error("kvm_write:write failed"); - return (0); - } else if (cc < len) - error("kvm_write:short write"); - return (cc); - } else - return (0); - } else { - printf("kvm_write not implemented for dead kernels\n"); - return (0); - } - /* NOTREACHED */ -} - -kvm_read(core_kd, memaddr, myaddr, len) -CORE_ADDR memaddr; -char *myaddr; -{ - return (kernel_core_file_hook (core_kd, memaddr, myaddr, len)); -} - -kvm_uread(core_kd, p, memaddr, myaddr, len) -register struct proc *p; -CORE_ADDR memaddr; -char *myaddr; -{ - register char *cp; - char procfile[MAXPATHLEN]; - ssize_t amount; - int fd; - - if (devmem) { - cp = myaddr; - - sprintf(procfile, "/proc/%d/mem", p->p_pid); - fd = open(procfile, O_RDONLY, 0); - - if (fd < 0) { - error("cannot open %s", procfile); - close(fd); - return (0); - } - - while (len > 0) { - if (lseek(fd, memaddr, 0) == -1 && errno != 0) { - error("invalid address (%x) in %s", - memaddr, procfile); - break; - } - amount = read(fd, cp, len); - if (amount < 0) { - error("error reading %s", procfile); - break; - } - cp += amount; - memaddr += amount; - len -= amount; - } - - close(fd); - return (ssize_t)(cp - myaddr); - } else { - return (kernel_core_file_hook (core_kd, memaddr, myaddr, len)); - } -} - -static struct kinfo_proc kp; - -/* - * try to do what kvm_proclist in libkvm would do - */ -int -kvm_proclist (cfd, pid, p, cnt) -int cfd, pid, *cnt; -struct proc *p; -{ - struct proc lp; - - for (; p != NULL; p = lp.p_list.le_next) { - if (!kvm_read(cfd, (CORE_ADDR)p, (char *)&lp, sizeof (lp))) - return (0); - if (lp.p_pid != pid) - continue; - kp.kp_eproc.e_paddr = p; - *cnt = 1; - return (1); - } - *cnt = 0; - return (0); -} - -/* - * try to do what kvm_deadprocs in libkvm would do - */ -struct kinfo_proc * -kvm_deadprocs (cfd, pid, cnt) -int cfd, pid, *cnt; -{ - CORE_ADDR allproc, zombproc; - struct proc *p; - - allproc = ksym_lookup("allproc"); - if (kvm_read(cfd, allproc, (char *)&p, sizeof (p)) == 0) - return (NULL); - kvm_proclist (cfd, pid, p, cnt); - if (!*cnt) { - zombproc = ksym_lookup("zombproc"); - if (kvm_read(cfd, zombproc, (char *)&p, sizeof (p)) == 0) - return (NULL); - kvm_proclist (cfd, pid, p, cnt); - } - return (&kp); -} - -/* - * try to do what kvm_getprocs in libkvm would do - */ -struct kinfo_proc * -kvm_getprocs (cfd, op, proc, cnt) -int cfd, op, *cnt; -CORE_ADDR proc; -{ - int mib[4], size; - - *cnt = 0; - /* assume it's a pid */ - if (devmem) { /* "live" kernel, use sysctl */ - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = (int)proc; - size = sizeof (kp); - if (sysctl (mib, 4, &kp, &size, NULL, 0) < 0) { - perror("sysctl"); - *cnt = 0; - return (NULL); - } - if (!size) - *cnt = 0; - else - *cnt = 1; - return (&kp); - } else - return (kvm_deadprocs (cfd, (int)proc, cnt)); -} - -static -physrd(cfd, addr, dat, len) -u_int addr; -char *dat; -{ - if (lseek(cfd, (off_t)addr, L_SET) == -1) - return (-1); - return (read(cfd, dat, len)); -} - -static CORE_ADDR -kvtophys (fd, addr) -CORE_ADDR addr; -{ - CORE_ADDR v; - unsigned int pte; - static CORE_ADDR PTD = -1; - CORE_ADDR current_ptd; -#ifdef DEBUG_KVTOPHYS - CORE_ADDR oldaddr = addr; -#endif - - /* - * If we're looking at the kernel stack, - * munge the address to refer to the user space mapping instead; - * that way we get the requested process's kstack, not the running one. - */ - /* - * this breaks xlating user addresses from a crash dump so only - * do it for a "live" kernel. - */ - if (devmem && addr >= kstack && addr < kstack + ctob(UPAGES)) - addr = (addr - kstack) + curpcb; - - /* - * We may no longer have a linear system page table... - * - * Here's the scoop. IdlePTD contains the physical address - * of a page table directory that always maps the kernel. - * IdlePTD is in memory that is mapped 1-to-1, so we can - * find it easily given its 'virtual' address from ksym_lookup(). - * For hysterical reasons, the value of IdlePTD is stored in sbr. - * - * To look up a kernel address, we first convert it to a 1st-level - * address and look it up in IdlePTD. This gives us the physical - * address of a page table page; we extract the 2nd-level part of - * VA and read the 2nd-level pte. Finally, we add the offset part - * of the VA into the physical address from the pte and return it. - * - * User addresses are a little more complicated. If we don't have - * a current PCB from read_pcb(), we use PTD, which is the (fixed) - * virtual address of the current ptd. Since it's NOT in 1-to-1 - * kernel space, we must look it up using IdlePTD. If we do have - * a pcb, we get the ptd from pcb_ptd. - */ - - if (INKERNEL(addr)) - current_ptd = sbr; - else if (found_pcb == 0) { - if (PTD == -1) - PTD = kvtophys(fd, ksym_lookup("PTD")); - current_ptd = PTD; - } else - current_ptd = pcb.pcb_cr3; - - /* - * Read the first-level page table (ptd). - */ - v = current_ptd + ((unsigned)addr >> PDRSHIFT) * sizeof pte; - if (physrd(fd, v, (char *)&pte, sizeof pte) < 0 || (pte&PG_V) == 0) - return (~0); - - /* - * Read the second-level page table. - */ - v = (pte&PG_FRAME) + ((addr >> PAGE_SHIFT)&(NPTEPG-1)) * sizeof pte; - if (physrd(fd, v, (char *) &pte, sizeof(pte)) < 0 || (pte&PG_V) == 0) - return (~0); - - addr = (pte & PG_FRAME) + (addr & PAGE_MASK); -#ifdef DEBUG_KVTOPHYS - printf("vtophys(%x) -> %x\n", oldaddr, addr); -#endif - return (addr); -} - -read_pcb (fd, uaddr) -CORE_ADDR uaddr; -{ - int i; - int *pcb_regs = (int *)&pcb; - int eip; - CORE_ADDR nuaddr = uaddr; - - /* need this for the `proc' command to work */ - if (INKERNEL(uaddr)) - nuaddr = kvtophys(fd, uaddr); - if (physrd(fd, nuaddr, (char *)&pcb, sizeof pcb) < 0) { - error("cannot read pcb at %#x\n", uaddr); - return (-1); - } - printf("current pcb at %#x\n", uaddr); - - /* - * get the register values out of the sys pcb and - * store them where `read_register' will find them. - */ - for (i = 0; i < 8; ++i) - supply_register(i, &pcb_regs[i+10]); - supply_register(8, &pcb_regs[8]); /* eip */ - supply_register(9, &pcb_regs[9]); /* eflags */ - for (i = 10; i < 13; ++i) /* cs, ss, ds */ - supply_register(i, &pcb_regs[i+9]); - supply_register(13, &pcb_regs[18]); /* es */ - for (i = 14; i < 16; ++i) /* fs, gs */ - supply_register(i, &pcb_regs[i+8]); - -#if 0 /* doesn't work ??? */ - /* Hmm... */ - if (target_read_memory(pcb_regs[5+10]+4, &eip, sizeof eip, 0)) - error("Cannot read PC."); - supply_register(8, &eip); /* eip */ -#endif - - /* XXX 80387 registers? */ -} - -/* - * read len bytes from kernel virtual address 'addr' into local - * buffer 'buf'. Return numbert of bytes if read ok, 0 otherwise. On read - * errors, portion of buffer not read is zeroed. - */ -kernel_core_file_hook(fd, addr, buf, len) - CORE_ADDR addr; - char *buf; - int len; -{ - int i; - CORE_ADDR paddr; - register char *cp; - int cc; - - cp = buf; - - while (len > 0) { - paddr = kvtophys(fd, addr); -#ifdef DEBUG_KCFH -if(!INKERNEL(addr)) -fprintf(stderr,"addr 0x%x, paddr 0x%x\n", addr, paddr); -#endif - if (paddr == ~0) { - bzero(buf, len); - break; - } - /* we can't read across a page boundary */ - i = min(len, PAGE_SIZE - (addr & PAGE_MASK)); - if ((cc = physrd(fd, paddr, cp, i)) <= 0) { - bzero(cp, len); - return (cp - buf); - } - cp += cc; - addr += cc; - len -= cc; - } - return (cp - buf); -} - -/* - * 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 (fr) -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), "calltrap") == 0) - frametype = tf_trap; - else if (strncmp (SYMBOL_NAME(sym), "Xresume", 7) == 0) - frametype = tf_interrupt; - else if (strcmp (SYMBOL_NAME(sym), "Xsyscall") == 0) - frametype = tf_syscall; - } - - switch (frametype) { - 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 + 16 + oEIP, 4)); - - case tf_syscall: - return (read_memory_integer (fr->frame + 8 + oEIP, 4)); -#undef oEIP - } -} - -CORE_ADDR -fbsd_kern_frame_chain (fr) -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), "calltrap") == 0) - frametype = tf_trap; - else if (strncmp (SYMBOL_NAME(sym), "Xresume", 7) == 0) - frametype = tf_interrupt; - else if (strcmp (SYMBOL_NAME(sym), "_Xsyscall") == 0) - frametype = tf_syscall; - } - - switch (frametype) { - case tf_normal: - return (read_memory_integer (fr->frame, 4)); - -#define oEBP offsetof(struct trapframe, tf_ebp) - - case tf_trap: - return (read_memory_integer (fr->frame + 8 + oEBP, 4)); - - case tf_interrupt: - return (read_memory_integer (fr->frame + 16 + oEBP, 4)); - - case tf_syscall: - return (read_memory_integer (fr->frame + 8 + oEBP, 4)); -#undef oEBP - } -} - -#endif /* KERNEL_DEBUG */ diff --git a/gnu/usr.bin/binutils/gdb/i386/kvm-fbsd.c b/gnu/usr.bin/binutils/gdb/i386/kvm-fbsd.c new file mode 100644 index 000000000000..9419b6a878d7 --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/i386/kvm-fbsd.c @@ -0,0 +1,941 @@ +/* Live and postmortem kernel debugging functions for FreeBSD. + Copyright 1996 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. */ + +#include "defs.h" + +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <sys/sysctl.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/user.h> +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "symtab.h" +#include "command.h" +#include "bfd.h" +#include "target.h" +#include "gdbcore.h" +#include <sys/stat.h> +#include <unistd.h> +#include <vm/vm.h> +#include <vm/vm_param.h> + +#include <machine/vmparam.h> +#include <machine/pcb.h> +#include <machine/frame.h> + +static void kcore_files_info PARAMS ((struct target_ops *)); + +static void kcore_close PARAMS ((int)); + +static void get_kcore_registers PARAMS ((int)); + +static int kcore_xfer_kmem PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +static int xfer_umem PARAMS ((CORE_ADDR, char *, int, int)); + +static CORE_ADDR ksym_lookup PARAMS ((const char *)); + +static int read_pcb PARAMS ((int, CORE_ADDR)); + +static struct proc * curProc PARAMS ((void)); + +static int set_proc_context PARAMS ((CORE_ADDR paddr)); + +static void kcore_open PARAMS ((char *filename, int from_tty)); + +static void kcore_detach PARAMS ((char *args, int from_tty)); + +static void set_proc_cmd PARAMS ((char *arg, int from_tty)); + +static CORE_ADDR kvtophys PARAMS ((int, CORE_ADDR)); + +static int physrd PARAMS ((int, u_int, char*, int)); + +static int kvm_open PARAMS ((const char *efile, char *cfile, char *sfile, + int perm, char *errout)); + +static int kvm_close PARAMS ((int fd)); + +static int kvm_write PARAMS ((int core_kd, CORE_ADDR memaddr, + char *myaddr, int len)); + +static int kvm_read PARAMS ((int core_kd, CORE_ADDR memaddr, + char *myaddr, int len)); + +static int kvm_uread PARAMS ((int core_kd, struct proc *p, + CORE_ADDR memaddr, char *myaddr, + int len)); + +static int kernel_core_file_hook PARAMS ((int fd, CORE_ADDR addr, + char *buf, int len)); + +static struct kinfo_proc * kvm_getprocs PARAMS ((int cfd, int op, + CORE_ADDR proc, int *cnt)); + +extern struct target_ops kcore_ops; /* Forward decl */ + +/* Non-zero means we are debugging a kernel core file */ +int kernel_debugging = 0; +int kernel_writablecore = 0; + +static char *core_file; +static int core_kd = -1; +static struct proc *cur_proc; +static CORE_ADDR kernel_start; + +/* + * 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)))) + + + +/* + * 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 (fr) +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), "calltrap") == 0) + frametype = tf_trap; + else if (strncmp (SYMBOL_NAME(sym), "Xresume", 7) == 0) + frametype = tf_interrupt; + else if (strcmp (SYMBOL_NAME(sym), "Xsyscall") == 0) + frametype = tf_syscall; + } + + switch (frametype) { + 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 + 16 + oEIP, 4)); + + case tf_syscall: + return (read_memory_integer (fr->frame + 8 + oEIP, 4)); +#undef oEIP + } +} + +CORE_ADDR +fbsd_kern_frame_chain (fr) +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), "calltrap") == 0) + frametype = tf_trap; + else if (strncmp (SYMBOL_NAME(sym), "Xresume", 7) == 0) + frametype = tf_interrupt; + else if (strcmp (SYMBOL_NAME(sym), "_Xsyscall") == 0) + frametype = tf_syscall; + } + + switch (frametype) { + case tf_normal: + return (read_memory_integer (fr->frame, 4)); + +#define oEBP offsetof(struct trapframe, tf_ebp) + + case tf_trap: + return (read_memory_integer (fr->frame + 8 + oEBP, 4)); + + case tf_interrupt: + return (read_memory_integer (fr->frame + 16 + oEBP, 4)); + + case tf_syscall: + return (read_memory_integer (fr->frame + 8 + oEBP, 4)); +#undef oEBP + } +} + +static CORE_ADDR +ksym_lookup (name) +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); +} + +static struct proc * +curProc () +{ + struct proc *p; + CORE_ADDR addr = ksym_lookup ("curproc"); + + if (kvread (addr, &p)) + error ("cannot read proc pointer at %x\n", addr); + return p; +} + +/* + * Set the process context to that of the proc structure at + * system address paddr. + */ +static int +set_proc_context (paddr) + CORE_ADDR paddr; +{ + struct proc p; + + if (paddr < kernel_start) + return (1); + + cur_proc = (struct proc *)paddr; +#ifdef notyet + set_kernel_boundaries (cur_proc); +#endif + + /* 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 (), 0); + return (0); +} + +/* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + +/* ARGSUSED */ +static void +kcore_close (quitting) + int quitting; +{ + inferior_pid = 0; /* Avoid confusion from thread stuff */ + + if (core_kd) + { + kvm_close (core_kd); + free (core_file); + core_file = NULL; + core_kd = -1; + } +} + +/* This routine opens and sets up the core file bfd */ + +static void +kcore_open (filename, from_tty) + char *filename; + int from_tty; +{ + const char *p; + struct cleanup *old_chain; + char buf[256], *cp; + int ontop; + CORE_ADDR addr; + struct pcb pcb; + + target_preopen (from_tty); + + unpush_target (&kcore_ops); + + if (!filename) + { + /*error (core_kd?*/ + error ( (core_kd >= 0)? + "No core file specified. (Use `detach' to stop debugging a core file.)" + : "No core file specified."); + } + + filename = tilde_expand (filename); + if (filename[0] != '/') + { + cp = concat (current_directory, "/", filename, NULL); + free (filename); + filename = cp; + } + + old_chain = make_cleanup (free, filename); + + /* + * gdb doesn't really do anything if the exec-file couldn't + * be opened (in that case exec_bfd is NULL). Usually that's + * no big deal, but kvm_open needs the exec-file's name, + * which results in dereferencing a NULL pointer, a real NO-NO ! + * So, check here if the open of the exec-file succeeded. + */ + if (exec_bfd == NULL) /* the open failed */ + error ("kgdb could not open the exec-file, please check the name you used !"); + + core_kd = kvm_open (exec_bfd->filename, filename, NULL, + kernel_writablecore? O_RDWR : O_RDONLY, "kgdb: "); + if (core_kd < 0) + perror_with_name (filename); + + /* 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; + ontop = !push_target (&kcore_ops); + + kernel_start = bfd_get_start_address (exec_bfd); /* XXX */ + + /* 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 ("panic: %s\n", buf); + } + + 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; + } + + /* we may need this later */ + cur_proc = (struct proc *)curProc (); + /* 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 (), 0); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +static void +kcore_detach (args, from_tty) + 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"); +} + +/* 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 (regno) + int regno; +{ + struct user *uaddr; + + /* find the pcb for the current process */ + if (kvread (&cur_proc->p_addr, &uaddr)) + error ("cannot read u area ptr for proc at %#x", cur_proc); + if (read_pcb (core_kd, (CORE_ADDR)&uaddr->u_pcb) < 0) + error ("cannot read pcb at %#x", &uaddr->u_pcb); +} + +static void +kcore_files_info (t) + struct target_ops *t; +{ + printf ("\t`%s'\n", core_file); +} + +static int +kcore_xfer_kmem (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; +{ + int n; + + if (!memaddr) + return (0); + + if (memaddr < kernel_start) + return xfer_umem (memaddr, myaddr, len, write); + + n = write ? + kvm_write (core_kd, memaddr, myaddr, len) : + kvm_read (core_kd, memaddr, myaddr, len) ; + + if (n < 0) + return 0; + return n; +} + +static int +xfer_umem (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; /* ignored */ +{ + int n; + struct proc proc; + + if (kvread (cur_proc, &proc)) + error ("cannot read proc at %#x", cur_proc); + n = kvm_uread (core_kd, &proc, memaddr, myaddr, len) ; + + if (n < 0) + return 0; + return n; +} + +static void +set_proc_cmd (arg, from_tty) + char *arg; + int from_tty; +{ + CORE_ADDR paddr; + struct kinfo_proc *kp; + int cnt = 0; + + if (!arg) + error_no_arg ("proc address for new current process"); + if (!kernel_debugging) + error ("not debugging kernel"); + + paddr = (CORE_ADDR)parse_and_eval_address (arg); + /* assume it's a proc pointer if it's in the kernel */ + if (paddr >= kernel_start) { + if (set_proc_context(paddr)) + error("invalid proc address"); + } else { + kp = kvm_getprocs(core_kd, KERN_PROC_PID, paddr, &cnt); + if (!cnt) + error("invalid pid"); + if (set_proc_context((CORE_ADDR)kp->kp_eproc.e_paddr)) + error("invalid proc address"); + } +} + + + +#define KERNOFF ((unsigned)KERNBASE) +#define INKERNEL(x) ((x) >= KERNOFF) + +static CORE_ADDR sbr; +static CORE_ADDR curpcb; +static CORE_ADDR kstack; +static int found_pcb; +static int devmem; +static int kfd; +static struct pcb pcb; + +/* substitutes for the stuff in libkvm which doesn't work */ +/* most of this was taken from the old kgdb */ + +/* we don't need all this stuff, but the call should look the same */ + +static int +kvm_open (efile, cfile, sfile, perm, errout) + const char *efile; + char *cfile; + char *sfile; /* makes this kvm_open more compatible to the one in libkvm */ + int perm; + char *errout; /* makes this kvm_open more compatible to the one in libkvm */ +{ + struct stat stb; + CORE_ADDR addr; + int cfd; + + if ((cfd = open (cfile, perm, 0)) < 0) + return (cfd); + + fstat (cfd, &stb); + if ((stb.st_mode & S_IFMT) == S_IFCHR + && stb.st_rdev == makedev (2, 0)) + { + devmem = 1; + kfd = open ("/dev/kmem", perm, 0); + } + + physrd (cfd, ksym_lookup ("IdlePTD") - KERNOFF, (char*)&sbr, sizeof sbr); + printf ("IdlePTD %x\n", sbr); + curpcb = ksym_lookup ("curpcb") - KERNOFF; + physrd (cfd, curpcb, (char*)&curpcb, sizeof curpcb); + kstack = ksym_lookup ("kstack"); + + found_pcb = 1; /* for vtophys */ + if (!devmem) + read_pcb (cfd, ksym_lookup ("dumppcb") - KERNOFF); + else + read_pcb (cfd, kvtophys (cfd, kstack)); + + return (cfd); +} + +static int +kvm_close (fd) + int fd; +{ + return (close (fd)); +} + +static int +kvm_write (core_kd, memaddr, myaddr, len) + int core_kd; + CORE_ADDR memaddr; + char *myaddr; +{ + int cc; + + if (devmem) + { + if (kfd > 0) + { + /* + * Just like kvm_read, only we write. + */ + errno = 0; + if (lseek (kfd, (off_t)memaddr, 0) < 0 + && errno != 0) + { + error ("kvm_write:invalid address (%x)", memaddr); + return (0); + } + cc = write (kfd, myaddr, len); + if (cc < 0) + { + error ("kvm_write:write failed"); + return (0); + } + else if (cc < len) + error ("kvm_write:short write"); + return (cc); + } + else + return (0); + } + else + { + printf ("kvm_write not implemented for dead kernels\n"); + return (0); + } + /* NOTREACHED */ +} + +static int +kvm_read (core_kd, memaddr, myaddr, len) + int core_kd; + CORE_ADDR memaddr; + char *myaddr; +{ + return (kernel_core_file_hook (core_kd, memaddr, myaddr, len)); +} + +static int +kvm_uread (core_kd, p, memaddr, myaddr, len) + int core_kd; + register struct proc *p; + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register char *cp; + char procfile[MAXPATHLEN]; + ssize_t amount; + int fd; + + if (devmem) + { + cp = myaddr; + + sprintf (procfile, "/proc/%d/mem", p->p_pid); + fd = open (procfile, O_RDONLY, 0); + + if (fd < 0) + { + error ("cannot open %s", procfile); + close (fd); + return (0); + } + + while (len > 0) + { + if (lseek (fd, memaddr, 0) == -1 && errno != 0) + { + error ("invalid address (%x) in %s", + memaddr, procfile); + break; + } + amount = read (fd, cp, len); + if (amount < 0) + { + error ("error reading %s", procfile); + break; + } + cp += amount; + memaddr += amount; + len -= amount; + } + + close (fd); + return (ssize_t) (cp - myaddr); + } + else + return (kernel_core_file_hook (core_kd, memaddr, myaddr, len)); +} + +static struct kinfo_proc kp; + +/* + * try to do what kvm_proclist in libkvm would do + */ +static int +kvm_proclist (cfd, pid, p, cnt) +int cfd, pid, *cnt; +struct proc *p; +{ + struct proc lp; + + for (; p != NULL; p = lp.p_list.le_next) { + if (!kvm_read(cfd, (CORE_ADDR)p, (char *)&lp, sizeof (lp))) + return (0); + if (lp.p_pid != pid) + continue; + kp.kp_eproc.e_paddr = p; + *cnt = 1; + return (1); + } + *cnt = 0; + return (0); +} + +/* + * try to do what kvm_deadprocs in libkvm would do + */ +static struct kinfo_proc * +kvm_deadprocs (cfd, pid, cnt) +int cfd, pid, *cnt; +{ + CORE_ADDR allproc, zombproc; + struct proc *p; + + allproc = ksym_lookup("allproc"); + if (kvm_read(cfd, allproc, (char *)&p, sizeof (p)) == 0) + return (NULL); + kvm_proclist (cfd, pid, p, cnt); + if (!*cnt) { + zombproc = ksym_lookup("zombproc"); + if (kvm_read(cfd, zombproc, (char *)&p, sizeof (p)) == 0) + return (NULL); + kvm_proclist (cfd, pid, p, cnt); + } + return (&kp); +} + +/* + * try to do what kvm_getprocs in libkvm would do + */ +static struct kinfo_proc * +kvm_getprocs (cfd, op, proc, cnt) +int cfd, op, *cnt; +CORE_ADDR proc; +{ + int mib[4], size; + + *cnt = 0; + /* assume it's a pid */ + if (devmem) { /* "live" kernel, use sysctl */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = (int)proc; + size = sizeof (kp); + if (sysctl (mib, 4, &kp, &size, NULL, 0) < 0) { + perror("sysctl"); + *cnt = 0; + return (NULL); + } + if (!size) + *cnt = 0; + else + *cnt = 1; + return (&kp); + } else + return (kvm_deadprocs (cfd, (int)proc, cnt)); +} + +static int +physrd (cfd, addr, dat, len) + int cfd; + u_int addr; + char *dat; + int len; +{ + if (lseek (cfd, (off_t)addr, L_SET) == -1) + return (-1); + return (read (cfd, dat, len)); +} + +static CORE_ADDR +kvtophys (fd, addr) + int fd; + CORE_ADDR addr; +{ + CORE_ADDR v; + unsigned int pte; + static CORE_ADDR PTD = -1; + CORE_ADDR current_ptd; + + /* + * If we're looking at the kernel stack, + * munge the address to refer to the user space mapping instead; + * that way we get the requested process's kstack, not the running one. + */ + /* + * this breaks xlating user addresses from a crash dump so only + * do it for a "live" kernel. + */ + if (devmem && addr >= kstack && addr < kstack + ctob (UPAGES)) + addr = (addr - kstack) + curpcb; + + /* + * We may no longer have a linear system page table... + * + * Here's the scoop. IdlePTD contains the physical address + * of a page table directory that always maps the kernel. + * IdlePTD is in memory that is mapped 1-to-1, so we can + * find it easily given its 'virtual' address from ksym_lookup(). + * For hysterical reasons, the value of IdlePTD is stored in sbr. + * + * To look up a kernel address, we first convert it to a 1st-level + * address and look it up in IdlePTD. This gives us the physical + * address of a page table page; we extract the 2nd-level part of + * VA and read the 2nd-level pte. Finally, we add the offset part + * of the VA into the physical address from the pte and return it. + * + * User addresses are a little more complicated. If we don't have + * a current PCB from read_pcb(), we use PTD, which is the (fixed) + * virtual address of the current ptd. Since it's NOT in 1-to-1 + * kernel space, we must look it up using IdlePTD. If we do have + * a pcb, we get the ptd from pcb_ptd. + */ + + if (INKERNEL (addr)) + current_ptd = sbr; + else if (found_pcb == 0) + { + if (PTD == -1) + PTD = kvtophys (fd, ksym_lookup ("PTD")); + current_ptd = PTD; + } + else + current_ptd = pcb.pcb_cr3; + + /* + * Read the first-level page table (ptd). + */ + v = current_ptd + ( (unsigned)addr >> PDRSHIFT) * sizeof pte; + if (physrd (fd, v, (char *)&pte, sizeof pte) < 0 || (pte&PG_V) == 0) + return (~0); + + /* + * Read the second-level page table. + */ + v = (pte&PG_FRAME) + ((addr >> PAGE_SHIFT)&(NPTEPG-1)) * sizeof pte; + if (physrd (fd, v, (char *) &pte, sizeof (pte)) < 0 || (pte&PG_V) == 0) + return (~0); + + addr = (pte & PG_FRAME) + (addr & PAGE_MASK); +#if 0 + printf ("vtophys (%x) -> %x\n", oldaddr, addr); +#endif + return (addr); +} + +static int +read_pcb (fd, uaddr) + int fd; + CORE_ADDR uaddr; +{ + int i; + int *pcb_regs = (int *)&pcb; + int eip; + CORE_ADDR nuaddr = uaddr; + + /* need this for the `proc' command to work */ + if (INKERNEL(uaddr)) + nuaddr = kvtophys(fd, uaddr); + + if (physrd (fd, nuaddr, (char *)&pcb, sizeof pcb) < 0) + { + error ("cannot read pcb at %x\n", uaddr); + return (-1); + } + printf ("current pcb at %x\n", uaddr); + + /* + * get the register values out of the sys pcb and + * store them where `read_register' will find them. + */ + for (i = 0; i < 8; ++i) + supply_register (i, (char *)&pcb_regs[i+10]); + supply_register (8, (char *)&pcb_regs[8]); /* eip */ + supply_register (9, (char *)&pcb_regs[9]); /* eflags */ + for (i = 10; i < 13; ++i) /* cs, ss, ds */ + supply_register (i, (char *)&pcb_regs[i+9]); + supply_register (13, (char *)&pcb_regs[18]); /* es */ + for (i = 14; i < 16; ++i) /* fs, gs */ + supply_register (i, (char *)&pcb_regs[i+8]); + +#if 0 /* doesn't work ??? */ + /* Hmm... */ + if (target_read_memory (pcb_regs[5+10]+4, &eip, sizeof eip, 0)) + error ("Cannot read PC."); + supply_register (8, (char *)&eip); /* eip */ +#endif + + /* XXX 80387 registers? */ +} + +/* + * read len bytes from kernel virtual address 'addr' into local + * buffer 'buf'. Return numbert of bytes if read ok, 0 otherwise. On read + * errors, portion of buffer not read is zeroed. + */ + +static int +kernel_core_file_hook (fd, addr, buf, len) + int fd; + CORE_ADDR addr; + char *buf; + int len; +{ + int i; + CORE_ADDR paddr; + register char *cp; + int cc; + + cp = buf; + + while (len > 0) + { + paddr = kvtophys (fd, addr); + if (paddr == ~0) + { + memset (buf, '\000', len); + break; + } + /* we can't read across a page boundary */ + i = min (len, PAGE_SIZE - (addr & PAGE_MASK)); + if ( (cc = physrd (fd, paddr, cp, i)) <= 0) + { + memset (cp, '\000', len); + return (cp - buf); + } + cp += cc; + addr += cc; + len -= cc; + } + return (cp - buf); +} + +struct target_ops kcore_ops = { + "kcore", /* to_shortname */ + "Kernel core dump file", /* to_longname */ + "Use a core file as a target. Specify the filename of the core file.", /* to_doc */ + kcore_open, /* to_open */ + kcore_close, /* to_close */ + find_default_attach, /* to_attach */ + kcore_detach, /* to_detach */ + NULL, /* to_resume */ + NULL, /* to_wait */ + get_kcore_registers, /* to_fetch_registers */ + NULL, /* to_store_registers */ + NULL, /* to_prepare_to_store */ + kcore_xfer_kmem, /* to_xfer_memory */ + kcore_files_info, /* to_files_info */ + NULL, /* to_insert_breakpoint */ + NULL, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + NULL, /* to_kill */ + NULL, /* to_load */ + NULL, /* to_lookup_symbol */ + find_default_create_inferior, /* to_create_inferior */ + NULL, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + NULL, /* to_thread_alive */ + 0, /* to_stop */ + kcore_stratum, /* to_stratum */ + NULL, /* to_next */ + 0, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 0, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_kcorelow() +{ + add_target (&kcore_ops); + add_com ("proc", class_obscure, set_proc_cmd, "Set current process context"); +} diff --git a/gnu/usr.bin/binutils/gdb/i386/nm.h b/gnu/usr.bin/binutils/gdb/i386/nm.h index ec85bd8cfaac..6affe1ac87b9 100644 --- a/gnu/usr.bin/binutils/gdb/i386/nm.h +++ b/gnu/usr.bin/binutils/gdb/i386/nm.h @@ -1,5 +1,5 @@ /* Native-dependent definitions for Intel 386 running BSD Unix, for GDB. - Copyright 1986, 1987, 1989, 1992 Free Software Foundation, Inc. + Copyright 1986, 1987, 1989, 1992, 1996 Free Software Foundation, Inc. This file is part of GDB. @@ -15,10 +15,12 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef NM_FREEBSD_H -#define NM_FREEBSD_H +#ifndef NM_FBSD_H +#define NM_FBSD_H + +#define ATTACH_DETACH /* Be shared lib aware */ #include "solib.h" @@ -29,10 +31,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <machine/vmparam.h> #define KERNEL_U_ADDR USRSTACK -/* #undef FLOAT_INFO */ /* No float info yet */ -#define FLOAT_INFO extern void i386_float_info (); \ - i386_float_info () - #define REGISTER_U_ADDR(addr, blockend, regno) \ (addr) = i386_register_u_addr ((blockend),(regno)); @@ -40,61 +38,81 @@ extern int i386_register_u_addr PARAMS ((int, int)); #define PTRACE_ARG3_TYPE char* -#define ATTACH_DETACH -#define KERNEL_DEBUG /* make structure definitions match up with those expected in solib.c */ - -#define link_object sod -#define lo_name sod_name -#define lo_library sod_library -#define lo_unused sod_reserved -#define lo_major sod_major -#define lo_minor sod_minor -#define lo_next sod_next - -#define link_map so_map -#define lm_addr som_addr -#define lm_name som_path -#define lm_next som_next -#define lm_lop som_sod -#define lm_lob som_sodbase -#define lm_rwt som_write -#define lm_ld som_dynamic -#define lm_lpd som_spd - -#define link_dynamic_2 section_dispatch_table -#define ld_loaded sdt_loaded -#define ld_need sdt_sods -#define ld_rules sdt_filler1 -#define ld_got sdt_got -#define ld_plt sdt_plt -#define ld_rel sdt_rel -#define ld_hash sdt_hash -#define ld_stab sdt_nzlist -#define ld_stab_hash sdt_filler2 -#define ld_buckets sdt_buckets -#define ld_symbols sdt_strings -#define ld_symb_size sdt_str_sz -#define ld_text sdt_text_sz -#define ld_plt_sz sdt_plt_sz - -#define rtc_symb rt_symbol -#define rtc_sp rt_sp -#define rtc_next rt_next - -#define ld_debug so_debug -#define ldd_version dd_version -#define ldd_in_debugger dd_in_debugger -#define ldd_sym_loaded dd_sym_loaded -#define ldd_bp_addr dd_bpt_addr -#define ldd_bp_inst dd_bpt_shadow -#define ldd_cp dd_cc - -#define link_dynamic _dynamic -#define ld_version d_version -#define ldd d_debug -#define ld_un d_un -#define ld_2 d_sdt - -#endif /* NM_FREEBSD_H */ +#define link_object sod +#define lo_name sod_name +#define lo_library sod_library +#define lo_unused sod_reserved +#define lo_major sod_major +#define lo_minor sod_minor +#define lo_next sod_next + +#define link_map so_map +#define lm_addr som_addr +#define lm_name som_path +#define lm_next som_next +#define lm_lop som_sod +#define lm_lob som_sodbase +#define lm_rwt som_write +#define lm_ld som_dynamic +#define lm_lpd som_spd + +#define link_dynamic_2 section_dispatch_table +#define ld_loaded sdt_loaded +#define ld_need sdt_sods +#define ld_rules sdt_filler1 +#define ld_got sdt_got +#define ld_plt sdt_plt +#define ld_rel sdt_rel +#define ld_hash sdt_hash +#define ld_stab sdt_nzlist +#define ld_stab_hash sdt_filler2 +#define ld_buckets sdt_buckets +#define ld_symbols sdt_strings +#define ld_symb_size sdt_str_sz +#define ld_text sdt_text_sz +#define ld_plt_sz sdt_plt_sz + +#define rtc_symb rt_symbol +#define rtc_sp rt_sp +#define rtc_next rt_next + +#define ld_debug so_debug +#define ldd_version dd_version +#define ldd_in_debugger dd_in_debugger +#define ldd_sym_loaded dd_sym_loaded +#define ldd_bp_addr dd_bpt_addr +#define ldd_bp_inst dd_bpt_shadow +#define ldd_cp dd_cc + +#define link_dynamic _dynamic +#define ld_version d_version +#define ldd d_debug +#define ld_un d_un +#define ld_2 d_sdt + +/* Return sizeof user struct to callers in less machine dependent routines */ + +#define KERNEL_U_SIZE kernel_u_size() +extern int kernel_u_size PARAMS ((void)); + +#define ADDITIONAL_OPTIONS \ + {"kernel", no_argument, &kernel_debugging, 1}, \ + {"k", no_argument, &kernel_debugging, 1}, \ + {"wcore", no_argument, &kernel_writablecore, 1}, \ + {"w", no_argument, &kernel_writablecore, 1}, + +#define ADDITIONAL_OPTION_HELP \ + "\ + --kernel Enable kernel debugging.\n\ + --wcore Make core file writable (only works for /dev/mem).\n\ + This option only works while debugging a kernel !!\n\ +" + +extern int kernel_debugging; +extern int kernel_writablecore; + +#define DEFAULT_PROMPT kernel_debugging?"(kgdb) ":"(gdb) " + +#endif /* NM_FBSD_H */ diff --git a/gnu/usr.bin/binutils/gdb/i386/tm.h b/gnu/usr.bin/binutils/gdb/i386/tm.h index f775da9cf81c..6b1dc068bac6 100644 --- a/gnu/usr.bin/binutils/gdb/i386/tm.h +++ b/gnu/usr.bin/binutils/gdb/i386/tm.h @@ -1,5 +1,5 @@ -/* Macro definitions for i386 running under BSD Unix. - Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. +/* Macro definitions for x86 running under FreeBSD Unix. + Copyright 1996 Free Software Foundation, Inc. This file is part of GDB. @@ -15,43 +15,33 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _FREEBSD_TM_H_ -#define _FREEBSD_TM_H_ -/* Override number of expected traps from sysv. */ -#define START_INFERIOR_TRAPS_EXPECTED 2 +#ifndef TM_FBSD_H +#define TM_FBSD_H 1 -/* Most definitions from sysv could be used. */ -#include "tm-i386v.h" +#include "i386/tm-i386bsd.h" -/* 386BSD cannot handle the segment registers. */ -/* BSDI can't handle them either. */ -/* FreeBSD cannot handle %fs or %gs. */ #undef NUM_REGS -#ifdef __FreeBSD__ #define NUM_REGS 14 -#else -#define NUM_REGS 10 -#endif -/* On 386 bsd, sigtramp is above the user stack and immediately below - the user area. Using constants here allows for cross debugging. - These are tested for BSDI but should work on 386BSD. */ -#define SIGTRAMP_START 0xfdbfdfc0 -#define SIGTRAMP_END 0xfdbfe000 +extern struct frame_info *setup_arbitrary_frame PARAMS ((int, CORE_ADDR *)); -/* The following redefines make backtracing through sigtramp work. - They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp - from the sigcontext structure which is pushed by the kernel on the - user stack, along with a pointer to it. */ +#define SETUP_ARBITRARY_FRAME(argc, argv) setup_arbitrary_frame (argc, argv) + +extern void i386_float_info PARAMS ((void)); + +#define FLOAT_INFO i386_float_info () + +#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) STREQ (name, "_DYNAMIC") /* FRAME_CHAIN takes a frame's nominal address and produces the frame's chain-pointer. In the case of the i386, the frame's nominal address is the address of a 4-byte word containing the calling frame's address. */ -#undef FRAME_CHAIN + extern CORE_ADDR fbsd_kern_frame_chain (struct frame_info *); +#undef FRAME_CHAIN #define FRAME_CHAIN(thisframe) \ (kernel_debugging ? fbsd_kern_frame_chain(thisframe) : \ ((thisframe)->signal_handler_caller \ @@ -60,25 +50,10 @@ extern CORE_ADDR fbsd_kern_frame_chain (struct frame_info *); ? read_memory_integer ((thisframe)->frame, 4) \ : 0))) -/* A macro that tells us whether the function invocation represented - by FI does not have a frame on the stack associated with it. If it - does not, FRAMELESS is set to 1, else 0. */ -#undef FRAMELESS_FUNCTION_INVOCATION -#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ - do { \ - if ((FI)->signal_handler_caller) \ - (FRAMELESS) = 0; \ - else \ - (FRAMELESS) = frameless_look_for_prologue(FI); \ - } while (0) - /* Saved Pc. Get it from sigcontext if within sigtramp. */ -/* Offset to saved PC in sigcontext, from <sys/signal.h>. */ -#define SIGCONTEXT_PC_OFFSET 20 - -#undef FRAME_SAVED_PC extern CORE_ADDR fbsd_kern_frame_saved_pc (struct frame_info *); +#undef FRAME_SAVED_PC #define FRAME_SAVED_PC(FRAME) \ (kernel_debugging ? fbsd_kern_frame_saved_pc(FRAME) : \ (((FRAME)->signal_handler_caller \ @@ -86,9 +61,4 @@ extern CORE_ADDR fbsd_kern_frame_saved_pc (struct frame_info *); : read_memory_integer ((FRAME)->frame + 4, 4)) \ )) -#undef SETUP_ARBITRARY_FRAME -#include "frame.h" -extern FRAME setup_arbitrary_frame (); -#define SETUP_ARBITRARY_FRAME setup_arbitrary_frame - -#endif /* _FREEBSD_TM_H_ */ +#endif /* TM_FBSD_H */ diff --git a/gnu/usr.bin/binutils/gdb/i386/version.c b/gnu/usr.bin/binutils/gdb/i386/version.c index 43f63d2c71ae..3d677fee3b68 100644 --- a/gnu/usr.bin/binutils/gdb/i386/version.c +++ b/gnu/usr.bin/binutils/gdb/i386/version.c @@ -1,3 +1,3 @@ -char *version = "4.13"; +char *version = "4.16"; char *host_name = "i386-unknown-freebsd"; char *target_name = "i386-unknown-freebsd"; diff --git a/gnu/usr.bin/binutils/gdb/i386/xm.h b/gnu/usr.bin/binutils/gdb/i386/xm.h index 6a71227aec77..8a852a29787c 100644 --- a/gnu/usr.bin/binutils/gdb/i386/xm.h +++ b/gnu/usr.bin/binutils/gdb/i386/xm.h @@ -15,15 +15,9 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define HOST_BYTE_ORDER LITTLE_ENDIAN #include <machine/limits.h> /* for INT_MIN, to avoid "INT_MIN redefined" warnings from defs.h */ - -/* psignal() is in <signal.h>. */ - -#define PSIGNAL_IN_SIGNAL_H - -#define HAVE_TERMIOS diff --git a/gnu/usr.bin/binutils/gdb/kvm-fbsd.c b/gnu/usr.bin/binutils/gdb/kvm-fbsd.c new file mode 100644 index 000000000000..9419b6a878d7 --- /dev/null +++ b/gnu/usr.bin/binutils/gdb/kvm-fbsd.c @@ -0,0 +1,941 @@ +/* Live and postmortem kernel debugging functions for FreeBSD. + Copyright 1996 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. */ + +#include "defs.h" + +#include <errno.h> +#include <signal.h> +#include <fcntl.h> +#include <sys/sysctl.h> +#include <sys/param.h> +#include <sys/time.h> +#include <sys/proc.h> +#include <sys/user.h> +#include "frame.h" /* required by inferior.h */ +#include "inferior.h" +#include "symtab.h" +#include "command.h" +#include "bfd.h" +#include "target.h" +#include "gdbcore.h" +#include <sys/stat.h> +#include <unistd.h> +#include <vm/vm.h> +#include <vm/vm_param.h> + +#include <machine/vmparam.h> +#include <machine/pcb.h> +#include <machine/frame.h> + +static void kcore_files_info PARAMS ((struct target_ops *)); + +static void kcore_close PARAMS ((int)); + +static void get_kcore_registers PARAMS ((int)); + +static int kcore_xfer_kmem PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *)); + +static int xfer_umem PARAMS ((CORE_ADDR, char *, int, int)); + +static CORE_ADDR ksym_lookup PARAMS ((const char *)); + +static int read_pcb PARAMS ((int, CORE_ADDR)); + +static struct proc * curProc PARAMS ((void)); + +static int set_proc_context PARAMS ((CORE_ADDR paddr)); + +static void kcore_open PARAMS ((char *filename, int from_tty)); + +static void kcore_detach PARAMS ((char *args, int from_tty)); + +static void set_proc_cmd PARAMS ((char *arg, int from_tty)); + +static CORE_ADDR kvtophys PARAMS ((int, CORE_ADDR)); + +static int physrd PARAMS ((int, u_int, char*, int)); + +static int kvm_open PARAMS ((const char *efile, char *cfile, char *sfile, + int perm, char *errout)); + +static int kvm_close PARAMS ((int fd)); + +static int kvm_write PARAMS ((int core_kd, CORE_ADDR memaddr, + char *myaddr, int len)); + +static int kvm_read PARAMS ((int core_kd, CORE_ADDR memaddr, + char *myaddr, int len)); + +static int kvm_uread PARAMS ((int core_kd, struct proc *p, + CORE_ADDR memaddr, char *myaddr, + int len)); + +static int kernel_core_file_hook PARAMS ((int fd, CORE_ADDR addr, + char *buf, int len)); + +static struct kinfo_proc * kvm_getprocs PARAMS ((int cfd, int op, + CORE_ADDR proc, int *cnt)); + +extern struct target_ops kcore_ops; /* Forward decl */ + +/* Non-zero means we are debugging a kernel core file */ +int kernel_debugging = 0; +int kernel_writablecore = 0; + +static char *core_file; +static int core_kd = -1; +static struct proc *cur_proc; +static CORE_ADDR kernel_start; + +/* + * 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)))) + + + +/* + * 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 (fr) +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), "calltrap") == 0) + frametype = tf_trap; + else if (strncmp (SYMBOL_NAME(sym), "Xresume", 7) == 0) + frametype = tf_interrupt; + else if (strcmp (SYMBOL_NAME(sym), "Xsyscall") == 0) + frametype = tf_syscall; + } + + switch (frametype) { + 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 + 16 + oEIP, 4)); + + case tf_syscall: + return (read_memory_integer (fr->frame + 8 + oEIP, 4)); +#undef oEIP + } +} + +CORE_ADDR +fbsd_kern_frame_chain (fr) +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), "calltrap") == 0) + frametype = tf_trap; + else if (strncmp (SYMBOL_NAME(sym), "Xresume", 7) == 0) + frametype = tf_interrupt; + else if (strcmp (SYMBOL_NAME(sym), "_Xsyscall") == 0) + frametype = tf_syscall; + } + + switch (frametype) { + case tf_normal: + return (read_memory_integer (fr->frame, 4)); + +#define oEBP offsetof(struct trapframe, tf_ebp) + + case tf_trap: + return (read_memory_integer (fr->frame + 8 + oEBP, 4)); + + case tf_interrupt: + return (read_memory_integer (fr->frame + 16 + oEBP, 4)); + + case tf_syscall: + return (read_memory_integer (fr->frame + 8 + oEBP, 4)); +#undef oEBP + } +} + +static CORE_ADDR +ksym_lookup (name) +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); +} + +static struct proc * +curProc () +{ + struct proc *p; + CORE_ADDR addr = ksym_lookup ("curproc"); + + if (kvread (addr, &p)) + error ("cannot read proc pointer at %x\n", addr); + return p; +} + +/* + * Set the process context to that of the proc structure at + * system address paddr. + */ +static int +set_proc_context (paddr) + CORE_ADDR paddr; +{ + struct proc p; + + if (paddr < kernel_start) + return (1); + + cur_proc = (struct proc *)paddr; +#ifdef notyet + set_kernel_boundaries (cur_proc); +#endif + + /* 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 (), 0); + return (0); +} + +/* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + +/* ARGSUSED */ +static void +kcore_close (quitting) + int quitting; +{ + inferior_pid = 0; /* Avoid confusion from thread stuff */ + + if (core_kd) + { + kvm_close (core_kd); + free (core_file); + core_file = NULL; + core_kd = -1; + } +} + +/* This routine opens and sets up the core file bfd */ + +static void +kcore_open (filename, from_tty) + char *filename; + int from_tty; +{ + const char *p; + struct cleanup *old_chain; + char buf[256], *cp; + int ontop; + CORE_ADDR addr; + struct pcb pcb; + + target_preopen (from_tty); + + unpush_target (&kcore_ops); + + if (!filename) + { + /*error (core_kd?*/ + error ( (core_kd >= 0)? + "No core file specified. (Use `detach' to stop debugging a core file.)" + : "No core file specified."); + } + + filename = tilde_expand (filename); + if (filename[0] != '/') + { + cp = concat (current_directory, "/", filename, NULL); + free (filename); + filename = cp; + } + + old_chain = make_cleanup (free, filename); + + /* + * gdb doesn't really do anything if the exec-file couldn't + * be opened (in that case exec_bfd is NULL). Usually that's + * no big deal, but kvm_open needs the exec-file's name, + * which results in dereferencing a NULL pointer, a real NO-NO ! + * So, check here if the open of the exec-file succeeded. + */ + if (exec_bfd == NULL) /* the open failed */ + error ("kgdb could not open the exec-file, please check the name you used !"); + + core_kd = kvm_open (exec_bfd->filename, filename, NULL, + kernel_writablecore? O_RDWR : O_RDONLY, "kgdb: "); + if (core_kd < 0) + perror_with_name (filename); + + /* 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; + ontop = !push_target (&kcore_ops); + + kernel_start = bfd_get_start_address (exec_bfd); /* XXX */ + + /* 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 ("panic: %s\n", buf); + } + + 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; + } + + /* we may need this later */ + cur_proc = (struct proc *)curProc (); + /* 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 (), 0); + print_stack_frame (selected_frame, selected_frame_level, 1); +} + +static void +kcore_detach (args, from_tty) + 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"); +} + +/* 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 (regno) + int regno; +{ + struct user *uaddr; + + /* find the pcb for the current process */ + if (kvread (&cur_proc->p_addr, &uaddr)) + error ("cannot read u area ptr for proc at %#x", cur_proc); + if (read_pcb (core_kd, (CORE_ADDR)&uaddr->u_pcb) < 0) + error ("cannot read pcb at %#x", &uaddr->u_pcb); +} + +static void +kcore_files_info (t) + struct target_ops *t; +{ + printf ("\t`%s'\n", core_file); +} + +static int +kcore_xfer_kmem (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; +{ + int n; + + if (!memaddr) + return (0); + + if (memaddr < kernel_start) + return xfer_umem (memaddr, myaddr, len, write); + + n = write ? + kvm_write (core_kd, memaddr, myaddr, len) : + kvm_read (core_kd, memaddr, myaddr, len) ; + + if (n < 0) + return 0; + return n; +} + +static int +xfer_umem (memaddr, myaddr, len, write) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; /* ignored */ +{ + int n; + struct proc proc; + + if (kvread (cur_proc, &proc)) + error ("cannot read proc at %#x", cur_proc); + n = kvm_uread (core_kd, &proc, memaddr, myaddr, len) ; + + if (n < 0) + return 0; + return n; +} + +static void +set_proc_cmd (arg, from_tty) + char *arg; + int from_tty; +{ + CORE_ADDR paddr; + struct kinfo_proc *kp; + int cnt = 0; + + if (!arg) + error_no_arg ("proc address for new current process"); + if (!kernel_debugging) + error ("not debugging kernel"); + + paddr = (CORE_ADDR)parse_and_eval_address (arg); + /* assume it's a proc pointer if it's in the kernel */ + if (paddr >= kernel_start) { + if (set_proc_context(paddr)) + error("invalid proc address"); + } else { + kp = kvm_getprocs(core_kd, KERN_PROC_PID, paddr, &cnt); + if (!cnt) + error("invalid pid"); + if (set_proc_context((CORE_ADDR)kp->kp_eproc.e_paddr)) + error("invalid proc address"); + } +} + + + +#define KERNOFF ((unsigned)KERNBASE) +#define INKERNEL(x) ((x) >= KERNOFF) + +static CORE_ADDR sbr; +static CORE_ADDR curpcb; +static CORE_ADDR kstack; +static int found_pcb; +static int devmem; +static int kfd; +static struct pcb pcb; + +/* substitutes for the stuff in libkvm which doesn't work */ +/* most of this was taken from the old kgdb */ + +/* we don't need all this stuff, but the call should look the same */ + +static int +kvm_open (efile, cfile, sfile, perm, errout) + const char *efile; + char *cfile; + char *sfile; /* makes this kvm_open more compatible to the one in libkvm */ + int perm; + char *errout; /* makes this kvm_open more compatible to the one in libkvm */ +{ + struct stat stb; + CORE_ADDR addr; + int cfd; + + if ((cfd = open (cfile, perm, 0)) < 0) + return (cfd); + + fstat (cfd, &stb); + if ((stb.st_mode & S_IFMT) == S_IFCHR + && stb.st_rdev == makedev (2, 0)) + { + devmem = 1; + kfd = open ("/dev/kmem", perm, 0); + } + + physrd (cfd, ksym_lookup ("IdlePTD") - KERNOFF, (char*)&sbr, sizeof sbr); + printf ("IdlePTD %x\n", sbr); + curpcb = ksym_lookup ("curpcb") - KERNOFF; + physrd (cfd, curpcb, (char*)&curpcb, sizeof curpcb); + kstack = ksym_lookup ("kstack"); + + found_pcb = 1; /* for vtophys */ + if (!devmem) + read_pcb (cfd, ksym_lookup ("dumppcb") - KERNOFF); + else + read_pcb (cfd, kvtophys (cfd, kstack)); + + return (cfd); +} + +static int +kvm_close (fd) + int fd; +{ + return (close (fd)); +} + +static int +kvm_write (core_kd, memaddr, myaddr, len) + int core_kd; + CORE_ADDR memaddr; + char *myaddr; +{ + int cc; + + if (devmem) + { + if (kfd > 0) + { + /* + * Just like kvm_read, only we write. + */ + errno = 0; + if (lseek (kfd, (off_t)memaddr, 0) < 0 + && errno != 0) + { + error ("kvm_write:invalid address (%x)", memaddr); + return (0); + } + cc = write (kfd, myaddr, len); + if (cc < 0) + { + error ("kvm_write:write failed"); + return (0); + } + else if (cc < len) + error ("kvm_write:short write"); + return (cc); + } + else + return (0); + } + else + { + printf ("kvm_write not implemented for dead kernels\n"); + return (0); + } + /* NOTREACHED */ +} + +static int +kvm_read (core_kd, memaddr, myaddr, len) + int core_kd; + CORE_ADDR memaddr; + char *myaddr; +{ + return (kernel_core_file_hook (core_kd, memaddr, myaddr, len)); +} + +static int +kvm_uread (core_kd, p, memaddr, myaddr, len) + int core_kd; + register struct proc *p; + CORE_ADDR memaddr; + char *myaddr; + int len; +{ + register char *cp; + char procfile[MAXPATHLEN]; + ssize_t amount; + int fd; + + if (devmem) + { + cp = myaddr; + + sprintf (procfile, "/proc/%d/mem", p->p_pid); + fd = open (procfile, O_RDONLY, 0); + + if (fd < 0) + { + error ("cannot open %s", procfile); + close (fd); + return (0); + } + + while (len > 0) + { + if (lseek (fd, memaddr, 0) == -1 && errno != 0) + { + error ("invalid address (%x) in %s", + memaddr, procfile); + break; + } + amount = read (fd, cp, len); + if (amount < 0) + { + error ("error reading %s", procfile); + break; + } + cp += amount; + memaddr += amount; + len -= amount; + } + + close (fd); + return (ssize_t) (cp - myaddr); + } + else + return (kernel_core_file_hook (core_kd, memaddr, myaddr, len)); +} + +static struct kinfo_proc kp; + +/* + * try to do what kvm_proclist in libkvm would do + */ +static int +kvm_proclist (cfd, pid, p, cnt) +int cfd, pid, *cnt; +struct proc *p; +{ + struct proc lp; + + for (; p != NULL; p = lp.p_list.le_next) { + if (!kvm_read(cfd, (CORE_ADDR)p, (char *)&lp, sizeof (lp))) + return (0); + if (lp.p_pid != pid) + continue; + kp.kp_eproc.e_paddr = p; + *cnt = 1; + return (1); + } + *cnt = 0; + return (0); +} + +/* + * try to do what kvm_deadprocs in libkvm would do + */ +static struct kinfo_proc * +kvm_deadprocs (cfd, pid, cnt) +int cfd, pid, *cnt; +{ + CORE_ADDR allproc, zombproc; + struct proc *p; + + allproc = ksym_lookup("allproc"); + if (kvm_read(cfd, allproc, (char *)&p, sizeof (p)) == 0) + return (NULL); + kvm_proclist (cfd, pid, p, cnt); + if (!*cnt) { + zombproc = ksym_lookup("zombproc"); + if (kvm_read(cfd, zombproc, (char *)&p, sizeof (p)) == 0) + return (NULL); + kvm_proclist (cfd, pid, p, cnt); + } + return (&kp); +} + +/* + * try to do what kvm_getprocs in libkvm would do + */ +static struct kinfo_proc * +kvm_getprocs (cfd, op, proc, cnt) +int cfd, op, *cnt; +CORE_ADDR proc; +{ + int mib[4], size; + + *cnt = 0; + /* assume it's a pid */ + if (devmem) { /* "live" kernel, use sysctl */ + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = (int)proc; + size = sizeof (kp); + if (sysctl (mib, 4, &kp, &size, NULL, 0) < 0) { + perror("sysctl"); + *cnt = 0; + return (NULL); + } + if (!size) + *cnt = 0; + else + *cnt = 1; + return (&kp); + } else + return (kvm_deadprocs (cfd, (int)proc, cnt)); +} + +static int +physrd (cfd, addr, dat, len) + int cfd; + u_int addr; + char *dat; + int len; +{ + if (lseek (cfd, (off_t)addr, L_SET) == -1) + return (-1); + return (read (cfd, dat, len)); +} + +static CORE_ADDR +kvtophys (fd, addr) + int fd; + CORE_ADDR addr; +{ + CORE_ADDR v; + unsigned int pte; + static CORE_ADDR PTD = -1; + CORE_ADDR current_ptd; + + /* + * If we're looking at the kernel stack, + * munge the address to refer to the user space mapping instead; + * that way we get the requested process's kstack, not the running one. + */ + /* + * this breaks xlating user addresses from a crash dump so only + * do it for a "live" kernel. + */ + if (devmem && addr >= kstack && addr < kstack + ctob (UPAGES)) + addr = (addr - kstack) + curpcb; + + /* + * We may no longer have a linear system page table... + * + * Here's the scoop. IdlePTD contains the physical address + * of a page table directory that always maps the kernel. + * IdlePTD is in memory that is mapped 1-to-1, so we can + * find it easily given its 'virtual' address from ksym_lookup(). + * For hysterical reasons, the value of IdlePTD is stored in sbr. + * + * To look up a kernel address, we first convert it to a 1st-level + * address and look it up in IdlePTD. This gives us the physical + * address of a page table page; we extract the 2nd-level part of + * VA and read the 2nd-level pte. Finally, we add the offset part + * of the VA into the physical address from the pte and return it. + * + * User addresses are a little more complicated. If we don't have + * a current PCB from read_pcb(), we use PTD, which is the (fixed) + * virtual address of the current ptd. Since it's NOT in 1-to-1 + * kernel space, we must look it up using IdlePTD. If we do have + * a pcb, we get the ptd from pcb_ptd. + */ + + if (INKERNEL (addr)) + current_ptd = sbr; + else if (found_pcb == 0) + { + if (PTD == -1) + PTD = kvtophys (fd, ksym_lookup ("PTD")); + current_ptd = PTD; + } + else + current_ptd = pcb.pcb_cr3; + + /* + * Read the first-level page table (ptd). + */ + v = current_ptd + ( (unsigned)addr >> PDRSHIFT) * sizeof pte; + if (physrd (fd, v, (char *)&pte, sizeof pte) < 0 || (pte&PG_V) == 0) + return (~0); + + /* + * Read the second-level page table. + */ + v = (pte&PG_FRAME) + ((addr >> PAGE_SHIFT)&(NPTEPG-1)) * sizeof pte; + if (physrd (fd, v, (char *) &pte, sizeof (pte)) < 0 || (pte&PG_V) == 0) + return (~0); + + addr = (pte & PG_FRAME) + (addr & PAGE_MASK); +#if 0 + printf ("vtophys (%x) -> %x\n", oldaddr, addr); +#endif + return (addr); +} + +static int +read_pcb (fd, uaddr) + int fd; + CORE_ADDR uaddr; +{ + int i; + int *pcb_regs = (int *)&pcb; + int eip; + CORE_ADDR nuaddr = uaddr; + + /* need this for the `proc' command to work */ + if (INKERNEL(uaddr)) + nuaddr = kvtophys(fd, uaddr); + + if (physrd (fd, nuaddr, (char *)&pcb, sizeof pcb) < 0) + { + error ("cannot read pcb at %x\n", uaddr); + return (-1); + } + printf ("current pcb at %x\n", uaddr); + + /* + * get the register values out of the sys pcb and + * store them where `read_register' will find them. + */ + for (i = 0; i < 8; ++i) + supply_register (i, (char *)&pcb_regs[i+10]); + supply_register (8, (char *)&pcb_regs[8]); /* eip */ + supply_register (9, (char *)&pcb_regs[9]); /* eflags */ + for (i = 10; i < 13; ++i) /* cs, ss, ds */ + supply_register (i, (char *)&pcb_regs[i+9]); + supply_register (13, (char *)&pcb_regs[18]); /* es */ + for (i = 14; i < 16; ++i) /* fs, gs */ + supply_register (i, (char *)&pcb_regs[i+8]); + +#if 0 /* doesn't work ??? */ + /* Hmm... */ + if (target_read_memory (pcb_regs[5+10]+4, &eip, sizeof eip, 0)) + error ("Cannot read PC."); + supply_register (8, (char *)&eip); /* eip */ +#endif + + /* XXX 80387 registers? */ +} + +/* + * read len bytes from kernel virtual address 'addr' into local + * buffer 'buf'. Return numbert of bytes if read ok, 0 otherwise. On read + * errors, portion of buffer not read is zeroed. + */ + +static int +kernel_core_file_hook (fd, addr, buf, len) + int fd; + CORE_ADDR addr; + char *buf; + int len; +{ + int i; + CORE_ADDR paddr; + register char *cp; + int cc; + + cp = buf; + + while (len > 0) + { + paddr = kvtophys (fd, addr); + if (paddr == ~0) + { + memset (buf, '\000', len); + break; + } + /* we can't read across a page boundary */ + i = min (len, PAGE_SIZE - (addr & PAGE_MASK)); + if ( (cc = physrd (fd, paddr, cp, i)) <= 0) + { + memset (cp, '\000', len); + return (cp - buf); + } + cp += cc; + addr += cc; + len -= cc; + } + return (cp - buf); +} + +struct target_ops kcore_ops = { + "kcore", /* to_shortname */ + "Kernel core dump file", /* to_longname */ + "Use a core file as a target. Specify the filename of the core file.", /* to_doc */ + kcore_open, /* to_open */ + kcore_close, /* to_close */ + find_default_attach, /* to_attach */ + kcore_detach, /* to_detach */ + NULL, /* to_resume */ + NULL, /* to_wait */ + get_kcore_registers, /* to_fetch_registers */ + NULL, /* to_store_registers */ + NULL, /* to_prepare_to_store */ + kcore_xfer_kmem, /* to_xfer_memory */ + kcore_files_info, /* to_files_info */ + NULL, /* to_insert_breakpoint */ + NULL, /* to_remove_breakpoint */ + NULL, /* to_terminal_init */ + NULL, /* to_terminal_inferior */ + NULL, /* to_terminal_ours_for_output */ + NULL, /* to_terminal_ours */ + NULL, /* to_terminal_info */ + NULL, /* to_kill */ + NULL, /* to_load */ + NULL, /* to_lookup_symbol */ + find_default_create_inferior, /* to_create_inferior */ + NULL, /* to_mourn_inferior */ + 0, /* to_can_run */ + 0, /* to_notice_signals */ + NULL, /* to_thread_alive */ + 0, /* to_stop */ + kcore_stratum, /* to_stratum */ + NULL, /* to_next */ + 0, /* to_has_all_memory */ + 1, /* to_has_memory */ + 1, /* to_has_stack */ + 1, /* to_has_registers */ + 0, /* to_has_execution */ + NULL, /* sections */ + NULL, /* sections_end */ + OPS_MAGIC /* to_magic */ +}; + +void +_initialize_kcorelow() +{ + add_target (&kcore_ops); + add_com ("proc", class_obscure, set_proc_cmd, "Set current process context"); +} |
